Hackathon 2026 · Verdict Logic Spec v2.1 — Context Handoff Brief

Is this me,
or the market?

Given a booking slump, return a deterministic verdict — is it a listing problem or a market problem — with a confidence score on the verdict line, plus the evidence and (light) next steps.

Agent: RM AI Agent Status: Draft for team discussion 6 blocking decisions 🟥
Section 1

Design principles

Agree these first — everything downstream assumes them.

1

Rules decide, the LLM narrates. The verdict and confidence are computed by fixed thresholds. The LLM only turns the computed result into customer-safe language. If the LLM decides "me vs market," we fail the eval's 4–5×-same-result requirement. This is the most important line in the doc.

2

Five verdict states, not two. No Slump · Market · Mixed · Me · Winning — plus two override states (On Strategy, Late Not Lost) and one abort state (Inconclusive). An agent that only ever says "me or market" is wrong about a third of the time.

3

Pace-matched, always. Every STLY comparison is on-the-books-now vs on-the-books-at-the-same-lead-time-last-year — never vs final realized STLY. This one rule prevents the most common false alarm.

4

Customer-safe by default. SCs forward the output. No comp identities, no owner-block snark, language that survives a paste into a customer email.

5

Diagnose, don't solve. Scope is the verdict + the lever, not a solution engine. We point at "relax min-stay here" / "DSO X% on this range," we don't build the fix.


Section 2

Where the logic came from

Four sources, and they converge on the same picture.

Soumyadeep (RM) — the verdict math

Four numbers — occ, occ-STLY, market-occ, market-occ-STLY. Two senses of underperformance: growth (not growing as fast as market) and absolute. Market context is everything (is the market up or down?). Flagged the traps: fall-foliage strategy listings, phantom occupancy (blocks read as occ in ski markets), priced-out-masquerading-as-low-ADR, RevPAR-negative "wins," like-to-like, large-unit comp dilution, weekday/weekend split.

Kyle (SC) — the diagnostic order

Visibility (sync, alerts, min-stay) supersedes pricing — check it first. Booking window + pickup (7/14/30-day; 7-day is noise). "Me" tells: far-out 61+ premium missing early bookings, misconfigured customizations, luxury tag on a standard unit. "Market" tells: market pacing behind, low pickup market-wide, cancelled events. Fix via DSO, not base-price moves.

Joaquin (SC) — the index math at scale

Segment/leaderboard pacing, MPI (occ vs market ×100), ADR index, RevPAR index. Reads MPI + ADR index together, judged against property tier. Notably does not use the Account Review helper for this question.

Account Review Helper — the shipped classifier

The classifier primitive with fixed, eval-stable thresholds. We adopt it verbatim as the core check and wrap it — we do not rebuild it.


Section 3

Relationship to the Account Review Helper & the pipeline

The shipped Account Review logic is our verdict primitive. We adopt its core check and thresholds verbatim. We do not rebuild it — the agent is the pace-matching layer before it and the RM judgment layer after it.

🟥 Blocking pre-req — Verification #1

Confirm whether the Account Review core check pace-matches STLY at equal lead time for future months, or compares against final realized STLY. If it does not pace-match, we must pace-match upstream and feed it matched numbers. Owner: Revanth (with Anish). Nothing downstream is trustworthy until this is answered.

The pipeline

0.  Resolve scope       (entity, window, KPI — default occ, ask)
1.  Pull data spine     (pace-matched 4 numbers + signals)   ← we pace-match here
2.  Validity gates      (comp size, like-to-like, phantom, sync, tier → set confidence / abort)
3.  Validate the claim  (is it even slow? maybe "No Slump", stop — ~⅓ exit here)
4.  Core check          (Account Review thresholds, verbatim → Under / At Par / Over)
5.  Market overlay      (+ market direction → Me / Market / Mixed / Winning)
6.  RevPAR overlay      (§5 On-Track logic → catch market-wide decline & the win-that-isn't)
7.  Booking-window veto (→ On Strategy / Late Not Lost)        ← not in helper
8.  Mechanism decompose (only if "me": visibility→settings→price→conversion)  ← not in helper, STRETCH
9.  Segment             (weekday/weekend, sub-windows, events)
10. Confidence score    (graduated, deterministic)            ← not in helper
11. Narrate             (LLM → customer-safe card)

Stages 4–6 are the helper running as-is. Stages 7, 8, 10 are the RM transcript logic. Stage 1 is where the two worldviews get reconciled.

Stage 8 is the scope edge

It's diagnosis, not solution, so it's in — but treat it as enrichment. Drop it under time pressure and the agent is still complete on Stages 3–7 + 10.


Section 4

Verdict states

Eight states, not two — five base verdicts plus two overrides and one abort.

StateMeaning
No SlumpPacing at/above own STLY and market — nothing wrong. Return proof, stop.
MarketYou fell ≈ as far as the market — not your fault. The "wait it out" answer.
MixedBoth down, you worse. Report split: market component vs self-inflicted component.
MeMarket held/rose, you fell. Listing-side gap.
WinningYou up, market down. Run underpricing caution (MPI ≫100 + low ADR index).
On Strategy (override)Looks like "Me" but it's a deliberate hold-high-liquidate-late pattern (short booking window, same as LY, LY hit target). Don't cut price.
Late Not Lost (override)Looks like "Me" but pickup is healthy and demand is arriving later (window compressed). Timing, not loss.
Inconclusive (abort)Data too weak to call (thin comps, dilution). Say so honestly.

Core check → state mapping: At Par + market up = No Slump · At Par + market down = Market · Under + market flat/up = Me · Under + market down = Mixed · Over = Winning. Then apply overrides/guards on top.


Section 5

Stage-by-stage logic

Every stage of the pipeline, in order — scope resolution through the customer-safe output contract.

Stage 0

Resolve scope

User inputs: entity (listing / group / comp-set level), stay-date range, KPI.

  • KPI defaults to occupancy but we ask, because RevPAR-driven users get a different verdict from the same data. Store the choice; it sets the primary axis.
  • 🟥 Decision: confirm the input surface — chat interface with date-range + entity picker (dropdown for listing/group/comp level). Owner: Shail / front-end.
Stage 1

Data spine (pace-matched)

Per window, for the chosen KPI, pull four numbers:

#Number
1Listing — on the books now
2Listing — STLY at matched lead time
3Comp set — on the books now
4Comp set — STLY at matched lead time

Supporting signals pulled alongside: listing & market booking window (current + STLY), 7/14/30-day pickup (listing + market), ADR index, RevPAR index, min-stay settings, sync status / system alerts, comp-set count, base-price tier setting.

🟥 Decision — data source

Report Builder API only exposes user-created templates. Revanth to confirm with Anish whether we get direct Report Builder API access so we can pull the pace-matched spine for any listing/window, not just pre-built templates.

Stage 2

Validity gates (run before any verdict)

Each gate adjusts confidence; some abort a window. Skipping these is what gets a verdict laughed out of a review.

GateRuleEffect
Comp-set size≥120 comps → full trust. <120 → dampen market weight (sliding). Large-unit dilution (e.g. 7–8BR pulling in 2–5BR) → flag.Confidence multiplier
Like-to-likeCompare vs STLY only if listing had ≥15 bookable nights at this point LY and this year. Else market-only.Drops STLY axis if failed
Market-data sanityDetect phantom occupancy — owner blocks read as occupancy in ski/off-season markets (the Vermont-Nov "7% that's really 0%" case). Flag thin future data.Suppress market axis for that window
Sync / alertsStale sync or active system alertsWarn — data may be wrong before logic runs
Comp-tier representativenessIf comps skew to one tier, ADR index is unreliableDown-weight ADR-based mechanism calls
🟥 Decision — thresholds

Like-to-like uses 15 bookable nights (from the helper). Comp trust floor 120 (Revanth). Confirm both, and define the sliding-dampening curve below 120.

Stage 3

Validate the claim

The RM's first move (Soumyadeep): a large share of "I'm slow" users are pacing fine or ahead. Run the core check; if the listing is at/above both its STLY pace and market pace → No Slump, return the proof table, stop. Target: ~⅓ of tickets exit here. The "why" in "why am I slow" is an implicit claim we test, not a fact we accept.

Stage 4

Core check (Account Review thresholds, verbatim)

Path A — has STLY (skip → At Par if STLY occ < 5%):

listing_%chg = listing_now − listing_STLY
market_%chg  = market_now  − market_STLY
diff         = listing_%chg − market_%chg
  diff < −5pp → Underperforming
  diff > +5pp → Overperforming
  else        → At Par
(if market side missing: use listing_%chg vs STLY alone, ±5pp)

Path B — no STLY / market-only (skip → At Par if market occ < 5%):

listing > 2pp below market AND relative gap worse than −5%  → Underperforming
listing 5%+ above market                                    → Overperforming
else                                                         → At Par

diff is our me-vs-market magnitude, already computable: the self-inflicted component = |diff| beyond the market move. No new math needed.

Stage 5

Market-direction overlay (3 labels → 5 states)

Overlay market_%chg direction onto the core-check label:

Core checkMarket directionVerdictMagnitude reported
At ParDownMarketmarket = market_%chg
At ParFlat / upNo Slump— (return proof, stop)
UnderFlat / upMeme = |diff|
UnderDownMixedmarket = market_%chg; me = |diff| beyond it
OveranyWinningrun overpricing / RevPAR caution

The Mixed decomposition ("market down 6pts, you're down 19, the 13 are yours") is the line that makes the verdict actionable instead of a shrug.

Market pickup as corroboration (Kyle)

The market direction above is read from occupancy pace (market_%chg). Corroborate it with market pickup: if market 14/30-day pickup is low across the board, that reinforces a Market/Mixed call; if the market is still picking up healthily while the listing isn't, that pushes toward Me. Pickup agreement/disagreement also feeds Stage 10 confidence.

Stage 6

RevPAR overlay (Account Review §5 On-Track logic)

Applied as a guardrail on every verdict, even when occupancy is the chosen KPI:

  • Market-wide decline: not underperforming but RevPAR < 95% STLY, and market also down → confirm Market, not a listing problem.
  • Win-that-isn't: occupancy looks strong but RevPAR < 95% STLY (LOS/discount crush) → do not report Winning; flag RevPAR-negative. (Soumyadeep's LOS trap.)
  • Priced-out masquerading as low ADR: occupancy low, ADR already below STLY, still underperforming → prices went so high bookings stopped; visible ADR is 1–2 cheap days. Detect via booking-window collapse. Do not recommend dropping price further.

RevPAR On-Track floor = 95% of STLY RevPAR (verbatim from helper §5).

Stage 7

Booking-window veto (not in the helper)

The helper will stamp the fall-foliage listing "Underperforming" because it's below market — the exact case that is actually fine. Guard it:

If listing booking window is materially shorter than market's and it was similarly short STLY (established pattern, not new) and LY final occupancy hit target → downgrade Me → On Strategy — monitor, re-check by [date].

Pickup cross-check: if bookings are still arriving (14/30-day pickup healthy) but late relative to the average window → Late Not Lost, distinct from both Me and Market.

Booking-window reference points (Kyle): 50%-by-market-booking-window rule; monitor from 180 days out for ~90-day windows; a shrinking average lead time signals a market trend. Use 14/30-day pickup as primary; 7-day alone is noise (post-holiday lulls).

The average is one number — read the shape around it (Kyle)

The booking window is an average, so don't judge off it alone: if the window is 30 days, look at what's happening 60 days out too. Are bookings landing within, ahead of, or behind the average window? That distribution is what distinguishes a genuine slowdown from a normal lead-time pattern, and it's the input to the Late Not Lost call above.

Stage 8

Mechanism decomposition (only if a "me" component)

Cheapest-and-most-visible first (Kyle: visibility supersedes pricing). Price is last.

  1. Visibility / availability. Sync active? Owner blocks? Min-stay wall (4-night min on a 2-night market)? Orphan gaps unfillable under current min-stay?
  2. Settings. Recommended settings on? Base-price tier realistic (luxury tag on a standard unit)? Far-out premium (PL 61+ day) pricing out before the window opens → missing early bookings? Aggressive LOS / OBA / step-OBA / stacked PSOs?
  3. Price position. ADR index vs comp set — against booked ADR where possible, read against tier (luxury >100 expected, budget <100). MPI ~70 + ADR index ~115 = priced-out with a number on it.
  4. Conversion residual. Priced at/below comps and still not booking → price is not the lever. Flag listing quality / reviews / photos / ranking / new supply cluster, and say "not a pricing problem." Refusing the reflexive discount here is what separates us from a naive tool.

Overperformance caution: MPI well above 100 is not automatically good — flag possible underpricing / over-aggressive discounting.

Stage 9

Segmentation

Run Stages 4–8 per weekday/weekend (day-of-week if available) and per sub-window (30/60/90 or per-month). It's routine to be market-soft in the next 30 and self-inflicted at 60–90, or fine weekdays and bleeding weekends. Call out events/holidays in range separately — for many users those windows are the account.

Stage 10

Confidence score (deterministic)

Confidence is a product of the gates, not a feeling. Bucket to High/Medium/Low, put it on the verdict line.

Inputs: comp-set size (≥120 full; sliding penalty below; heavy penalty on large-unit dilution) · like-to-like available (both axes) vs market-only · lead-time / future-data thinness · market-data sanity (phantom-block risk) · comp-tier representativeness · signal agreement (do MPI, pace delta, and pickup all point the same way? 3-way agree = High; conflict = Medium at best).

A 2-listing account at 90 days out with 40 comps → Inconclusive — Low, re-check in 14 days. Saying so is a feature.

🟥 Decision

Exact weighting / formula for the score. Proposal: multiplicative gate penalties → 0–1 scalar → banded. Team to set band cutoffs.

Stage 11

Output contract

  1. Verdict line + confidence. e.g. "Mixed — market down 6 pts, you're down 19; the 13-pt gap is yours. Medium confidence."
  2. Evidence table — 3 rows (you / comp set / delta); columns: on-the-books occ, pace vs matched STLY, MPI, ADR index, RevPAR index, 14/30-day pickup. This is the screenshot the SC pastes to the customer.
  3. Per-window + weekday/weekend breakdown, a verdict each.
  4. Mechanism ranking (only if a me-component) with supporting numbers.
  5. Next steps — the lever only: relax min-stay on these dates / DSO X% on this range — never a base-price move that wrecks well-priced dates. (Kyle: DSO over base-price for period-specific lag.)
  6. What would change this call — re-check date + the 1–2 metrics that would flip it.
  7. Data caveats — comp count, listings excluded by like-to-like, whether STLY is fair.

Section 6

Threshold config block (single source of truth)

Every tunable value in one place, with its source and confirmation status.

ParamValueSourceStatus
STLY spread tolerance±5 ppHelper §1.3adopt
Min STLY occupancy5%Helperadopt
Min market occupancy5%Helperadopt
Market absolute diff−2 ppHelperadopt
Market relative under−5%Helperadopt
Market relative over+5%Helperadopt
RevPAR On-Track floor95% STLY RevPARHelper §5adopt
Like-to-like min nights15Helper §4confirm
Comp trust floor120Revanthconfirm
Comp dampening curve <120TBD—🟥 define
Booking-window "materially shorter" bandTBDSoumyadeep🟥 define
Pickup primary window14 / 30 dayKyleadopt
Confidence band cutoffsTBD—🟥 define

Section 7

Latest open thread — the response-card contract

The target output is short: a verdict line, 2–3 evidence sentences, one tool pointer, a confidence + comp-set footer. Getting that short output right turned out to depend on data the pipeline hasn't specified yet. Four gaps, in the order they block the build.

1. Which comp set sets the confidence — pricing or market?

The card in front of us calls out a 5-listing comp set as HIGH confidence. But §6's comp trust floor of 120 was written for market/neighborhood data. Those are two different populations with opposite confidence curves:

BasisWhat it isConfidence curve
Pricing comp set~5 hand-matched comps used for the listing's own price recommendationSmall is fine — 5 well-matched comps = HIGH
Market / neighborhood dataThe full local pool (could be 100s of listings)Small is unreliable — needs ≥120 to trust (§6)

🟥 Decision needed before any threshold is coded: pick one as the card's primary comparison (current lean: pricing comp set as the headline, market data as a fallback when the comp set is thin) and write two separate confidence-threshold tables — one per basis. Coding a single threshold set against the wrong population is how the card ends up over- or under-confident.

2. The card needs per-listing numbers, not just the comp-set average

Two lines in the target card only work if we can count individual comps, not just average them:

  • "3 of 5 comps ≥65% occupancy" — needs each comp's own forward pacing number, so we can count how many clear a bar. An aggregate average can't produce this sentence.
  • "4 of 5 comps below their own October average" — needs each comp's own historical baseline, so we can compare every comp to itself, not to the group.

🟥 Confirm before writing any narration code: does the PriceLabs MCP surface expose per-comp forward pacing and per-comp historical averages, or only the comp-set aggregate? If it's aggregate-only, these two lines can't be built, and the card collapses back to a bare level gap ("48% vs 51%") — which is exactly the failure mode Section 5's design principles forbid.

3. Two internal signals need a plain-English translation

  • Match quality. Internally we have a tier-representativeness gate (does the comp set skew to one unit size/tier?). The card needs a one-word customer label for it — e.g. "well-matched" vs "loosely matched" — derived from that gate, not invented per-response by the LLM.
  • "Normal variance." Internally this is the ±5pp tolerance band from the core check. The card needs a fixed phrase for it ("within normal variance") that's always triggered by the same numeric condition, never phrased freely.

4. Card layout: compact by default, numbers on request

Ship the short card (verdict → evidence sentences → tool pointer → confidence footer) as the default response. Keep the full evidence table (per-window, per-segment, all raw numbers) behind an expandable "show the numbers" — not inline in the default reply.

Consistency rule to hold

The level gap (52% vs 68%) is presentation — a headline number. The per-comp distribution and ADR index are the evidence that justifies the verdict. Never let the LLM emit a verdict sentence from the level gap alone; it must always be backed by the distribution numbers from Stage 4–6.


Section 8

Open decisions summary

Walk into any working session wanting these closed.

1 🟥 Does the Account Review core check pace-match future STLY, or use final realized STLY? Everything depends on it. (Revanth ↔ Anish)
2 🟥 Report Builder API access for arbitrary listing/window pulls, vs only pre-built templates. (Revanth ↔ Anish)
3 🟥 Comparison basis: curated comp set vs market data as primary — sets the confidence model. (§7.1)
4 🟥 Per-comp data availability — does MCP expose per-listing forward pacing + per-listing history? (§7.2/7.3)
5 🟥 Growth-sense vs absolute-sense: does the verdict fire on growth-lag alone, or min(growth-lag, absolute-lag)? Changes which listings flag.
6 🟥 Numeric values still to set: comp dampening curve <120, booking-window band, confidence formula.
7 Stage 8 (mechanism) in-scope or stretch for the hackathon.

Section 9

Worked case studies

One question, ten data situations. Question throughout: "Are my bookings slow for October — me or the market?" Scope: single listing · window = October · KPI = occupancy · today ≈ 15–45 days out. All figures are invented to illustrate the logic path; occupancy is pace-matched (on-the-books-now vs same-lead-time LY).

Quick-reference matrix

Listing pace (ΔL)Market pace (ΔM)Base verdict
Up, but slower than marketUpMe
Down ≈ same as marketDownMarket
Down more than marketDownMixed
Tracking STLY & marketFlat/UpNo Slump
UpDownWinning (+ underpricing caution)

Overrides sit on top of the base verdict: a booking-window strategy pattern → On Strategy; healthy-but-late pickup → Late Not Lost; weak data → Inconclusive. Two guards can invert the obvious read entirely (cases I, J).

Master data table

Reading order per row: how the listing moved vs LY, how the market moved vs LY, then diff = the listing's move minus the market's move. diff < −5 reads as Under, diff > +5 as Over, otherwise At Par — that reading, plus the market's own direction, is what produces the final verdict.

CaseListing: LY → nowMarket: LY → nowdiffWhat's happeningVerdict
A44 → 48 ▲+452 → 63 ▲+11−7Both growing, but the listing is growing much slower than the market.Me
B55 → 41 ▼−1460 → 46 ▼−140Both fell by the same amount — the listing didn't lose any ground.Market
C55 → 38 ▼−1754 → 48 ▼−6−11Both fell, but the listing fell much further than the market did.Mixed
D51 → 58 ▲+756 → 60 ▲+4+3Listing is growing at least as fast as the market. Nothing wrong.No Slump
E50 → 62 ▲+1248 → 45 ▼−3+15Listing grew while the market shrank — but check: is it underpriced?Winning ⚠
F28 → 30 ▲+244 → 55 ▲+11−9Reads like "Me" — but this is the same short booking window as LY, which finished on target.On Strategy
G50 → 40 ▼−1056 → 58 ▲+2−12Reads like "Me" — but pickup is strong and the whole market is booking later this year.Late Not Lost
H30 → 35 ▲+544 → 50 ▲+6−1Numbers say At Par, but the comp set is too small/skewed to trust that read.Inconclusive
I34 → 22 ▼−1238 → 40 ▲+2−14This is the listing — but the fix is not another price cut (rates were already too high).Me
J60 → 78 ▲+1857 → 55 ▼−2+20Occupancy is up, but it was bought with a rate cut — not a clean win.Not a clean win

Case H's diff is technically "At Par," but with only 45 comps skewed toward smaller units, the market read itself can't be trusted — see the case note below.

Case notes

AMeHigh confidence
diff −7pp (Under) ΔL +4 · ΔM +11 MPI 85→76 ADR index 108 Booking window 25 vs mkt 30 (unchanged vs LY) Min-stay 3 on 2-night market

Core check fires Under (Stage 4); market is up so the overlay lands on Me (Stage 5). Booking window is unchanged from LY, so the Stage 7 veto doesn't fire. ADR index 108 + MPI 76 = priced above comparable booked rates while under-occupied — mechanism decomposition (Stage 8) points to price position, then min-stay. All four signals (core check, MPI, ADR index, booking-window stability) agree, so confidence is High.

"This is mostly you — the market is up +11, you're up only +4, so you've slipped from 85% to 76% of market occupancy. Primary lever: price position; secondary: min-stay."

BMarketHigh confidence
diff 0pp (At Par) ΔL −14 · ΔM −14 MPI 92→89 RevPAR <95% STLY (listing and market)

Core check lands At Par (diff = 0 pp exactly — Stage 4); market direction is down, so the overlay is Market (Stage 5). The Stage 6 RevPAR overlay confirms it: RevPAR is below the 95%-of-STLY floor for the listing, but the market's RevPAR is down too, which is what §5.2 "market-wide decline" checks for — this rules out a listing-side RevPAR problem. MPI barely moved (92→89), so share held. High confidence: core check, RevPAR overlay, and MPI all agree.

"It's the market, not you — October demand is down ~14 pts across the board and your share held. Cutting price won't fix a market-wide dip; hold and re-check." This is the "wait it out" answer, and it's the one that stops a needless price war.

CMixedHigh confidence
diff −11pp (Under) ΔL −17 · ΔM −6 MPI 102→79 Market component −6pp · Self-inflicted −11pp

Core check is Under; market is also down, so the overlay lands on Mixed (Stage 5). The decomposition splits diff into the market's own move (−6pp, not your fault) and the self-inflicted remainder (−11pp, the part beyond what the market explains). MPI falling from 102 to 79 — crossing from above-market to meaningfully below — corroborates a real listing-side slide, not noise.

"Mixed — the market softened 6 pts, but you're down 17; roughly 11 of those points are yours. Part wait-it-out, part fix."

DNo Slump
diff +3pp (At Par) ΔL +7 · ΔM +4 MPI 91→97

Core check lands At Par and the market is up, so Stage 5's overlay exits immediately at Stage 3 — before the RevPAR/veto/mechanism stages even run. MPI rising from 91 to 97 confirms share is improving, not just holding. This is the "no work to do" branch by design — the claim ("I'm slow") is tested and rejected on the numbers alone.

"No slump — you're pacing ahead of last year and holding your share. Nothing to fix here." Roughly a third of real tickets should land here; saying "you're fine" with proof is a feature, not a cop-out.

EWinning, with a caution
diff +15pp (Over) ΔL +12 · ΔM −3 MPI 138 ADR index 88

Core check is Over → base verdict is Winning (Stage 5). But Stage 8's overperformance check reads MPI and ADR index together: MPI 138 (well above 100) paired with ADR index 88 (booked rates below comps) is the specific signature of underpricing, not skill — the caution fires precisely because both numbers point the same direction.

"You're beating a soft market — but MPI 138 with ADR index 88 suggests you're underpriced. Worth testing higher rates before assuming this is pure skill."

FOn Strategyveto overrides "Me"
diff −9pp (Under → raw "Me") ΔL +2 · ΔM +11 Booking window 14 vs mkt 35 (LY: 13, same pattern) LY final occupancy: hit target

The core check alone says Me (diff −9pp, market rising). The Stage 7 veto is what overrides it: booking window is 14 days vs the market's 35 — but it was 13 days LY too (an established pattern, not new), and that LY pattern finished at target occupancy. All three veto conditions are met, so Me downgrades to On Strategy.

"Looks like underperformance, but this matches your deliberate late-booking pattern — identical to last year, which finished full. Monitor, re-check by [date]. Don't cut price." Firing "Me" here would be the agent's most embarrassing mistake; the veto is what prevents it.

GLate Not Lostveto overrides "Me"
diff −12pp (Under → raw "Me") ΔL −10 · ΔM +2 14/30-day pickup: strong, rising Market booking window: compressed vs LY

Core check again says Me (diff −12pp). But the Stage 7 pickup cross-check catches it: pickup is strong and rising, and the whole market's booking window has compressed vs LY — a market-wide shift to later bookings, not a listing-specific drop-off. That combination routes to Late Not Lost instead of Me.

"On today's snapshot this reads as you, but your pickup is strong and the whole market is booking later this year. This is timing, not a lost-booking problem — hold, re-check in 14 days. If pickup stalls, it flips to Me."

HInconclusiveLow confidence
diff −1pp (At Par — untrusted) ΔL +5 · ΔM +6 Comp count 45 (floor: 120) 6BR listing, comps skew 2–4BR

The raw core check reads At Par, but Stage 2's validity gates catch two problems before that number is trusted: comp count is 45, well under the 120 floor, and the comp set is diluted by smaller units against a 6BR listing. Both gates fire, so confidence bottoms out at Low regardless of what diff says — the agent reports the listing's own pace (+5 vs LY) as the only number it will stand behind.

"Signal's too weak to call cleanly — the comp set is only 45 listings and skewed to smaller units, so the market comparison isn't reliable for a 6BR. Best available: you're pacing +5 vs last year. Re-check in 14 days as more October bookings land." Refusing to fake a verdict is the honest move.

IMeguard: priced-out masquerading as low ADR
diff −14pp (Under) ΔL −12 · ΔM +2 Realized ADR: below own STLY Booking window: collapsed

Core check says Me (diff −14pp, market flat/up). Realized ADR already sitting below its own STLY would normally point to under-pricing — the naive read is "drop price." But Stage 6's priced-out check looks at the booking-window collapse instead: asking prices ran high enough, early enough, that demand stopped booking; the handful of bookings that did land were the cheap leftover days, which is what's dragging the realized-ADR average down. Verdict stays Me, but the guard changes which lever fires.

"This is you — but the fix is not another price cut. Your rates ran high enough earlier that demand dried up; the low ADR you see is just a couple of discounted days. Review the far-out pricing, don't discount further."

JGuard: RevPAR-negative "win"
diff +20pp (Over → raw "Winning") ΔL +18 · ΔM −2 RevPAR <95% STLY Driven by aggressive LOS discounting

Core check is Over into a flat/down market — by the base mapping alone this is Winning. The Stage 6 RevPAR overlay is what stops it from being reported that way: RevPAR sits below the 95%-of-STLY floor because ADR was cut via aggressive length-of-stay discounts. Occupancy went up, but revenue per available night went down — the "win-that-isn't" guard fires and the verdict is downgraded to a caution rather than a clean Winning.

"Occupancy looks great, but you bought it with rate — RevPAR is down vs last year, so this isn't the win it appears to be. Check your LOS discounting before celebrating the occupancy." This is why RevPAR sits as a guardrail on every verdict, even when occupancy is the chosen KPI.

What the ten cases prove

The same pipeline, fed only different numbers, produces "it's you," "it's the market," "you're fine," "don't cut price," and "that's not really a win" — each with a confidence level and a reason. Three cases (F, G, I) would be called wrong by any tool that reads the occupancy numbers alone — the veto and guards are the difference between a real RM verdict and a naive one. That contrast is the demo.

Verdict states recap: No Slump · Market · Mixed · Me · Winning, with overrides On Strategy / Late Not Lost and abort Inconclusive. Rules compute; LLM narrates; output is customer-safe.