Methodology Reference · Investment Framework
The Strategy Report
Methodology & Investment Framework — written so a careful reader with
no finance background can follow it end to end. Covers the deterministic signal engine,
the fair-value ensemble, the risk and tax architecture, the human-conviction override, the
forward track record, and the tightly-governed LLM narration layer behind the
“Market Intelligence Brief.”
CW
How to read this document
Every technical section is followed by a green
“In plain terms” box that restates the idea in everyday language with a real-world
analogy. If you only read the plain-terms boxes and the tables, you will still understand the whole
framework. The order is deliberate: we start with a Fundamentals primer (§0) that
defines every building block, so nothing later assumes prior knowledge. Length is on purpose — this
is a reference, not a brochure.
What this is — and isn’t
This is a rules-based analytical tool, not advice. Its SELL / TRIM / HOLD / ADD outputs are starting
points for your own judgement — they are not a registered adviser’s tailored recommendation
under NI 31-103, nothing is individualized advice, and nothing executes automatically. See §17.
The one idea to keep in mind
The report separates doing the maths from writing the words. All
the numbers and decisions come from fixed, tested computer code (the “engine”). A large language
model (the “AI”) only explains and prioritises them in plain English — it is never allowed to invent
a number, a price, or a “sell.” That separation removes one whole category of error — the AI cannot
fabricate a price or a verdict — but it does not, by itself, make every number right: the engine’s own
models and thresholds are judgement calls, disclosed and logged so they can be graded forward (§14) — none of the verdicts has yet been tested against returns.
Abstract
The Strategy Report is a per-account portfolio
diagnostic that fuses a deterministic, rules-based signal engine with a
governed large-language-model (LLM) narration layer. The engine owns all
quantitative work — fundamental quality scoring, a dispersion-aware multi-model fair-value ensemble,
27 signal rules with explicit precedence, concentration and drawdown risk analytics (now
regime-aware), Canadian tax logic, a documented human-conviction override, and a measurement-only
forward track record. The LLM performs exposition and prioritisation only: it cannot
fabricate a price, a fair value, a SELL, or a security outside the screened universe. The output is
a goal-anchored, tax-aware action plan — sized in shares and native-currency dollars, grouped by
registered/non-registered account, with an explicit audit trail of any rule the model overrode. The
verdicts (SELL/TRIM/HOLD/ADD) are deterministic rule outputs for the investor’s own consideration —
not a registered adviser’s recommendation under NI 31-103; nothing is tailored advice and nothing
executes automatically.
Separation of duties (the central design tenet)
Quant is computed once in version-controlled, unit-tested code (reproducible, deterministic). The
LLM is a translation/curation layer, not a calculator. This is what makes the brief defensible
under scrutiny: every figure traces to a rule, not to model confabulation.
00
Fundamentals primer — the building blocks
Definitions, in plain language, for every term the rest of the document uses. Skim
it now; refer back as needed.
Quality vs. price — two different questions
The framework keeps two questions strictly apart. “Is this a good business?” is
about quality — profits, debt, growth durability. “Is the share a good price right
now?” is about valuation. A wonderful business can be a poor buy if it’s expensive, and a
weak business can look cheap and still be a trap. Mixing the two is the classic mistake; we never do.
Deep Score (0–100)
Our single quality grade for a business, built from a 16-point value-investing checklist:
profitability (return on equity/capital, margins), growth (revenue and earnings over years),
balance-sheet strength (debt, free-cash-flow consistency), valuation discipline, and a moat/quality
factor. It deliberately ignores the share price — it grades the company, not the
stock chart — so price and momentum can sharpen a decision without contaminating
the quality read. Bands: ≥85 exceptional, 70–84 high quality, 55–69 acceptable, 40–54 middling,
below 40 “avoid.”
Fair value — a range, not a number
Our estimate of what a share is actually worth, produced by blending several independent valuation
models (see §6). We never publish a single fake-precise figure; we publish a low–high range
and a confidence level (e.g. “C$240–C$320, medium confidence”). A price inside the
range is fairly valued; above the top is genuinely expensive; below the bottom is a
genuine discount.
Concentration, weight & “look-through”
Weight is how big a position is. Per-account weight is its size
inside one account; aggregate (look-through) weight is its total size across
every account you own. The aggregate is the number that matters — the same stock held in a TFSA and an
RRSP is one bet, and per-account numbers hide that. Concentration is having
too much in one stock, one industry, or one currency.
Market regime
A plain label for “what kind of market are we in right now,” read from interest rates, the yield
curve, credit spreads, volatility (VIX), and whether the market is above its long-term trend line. The
four regimes are expansion (calm, risk-on), recovery (climbing out
of trouble), late-cycle (getting toppy, caution), and contraction
(stress/downturn). We never predict a price; we just describe the weather. If any of those five
readings could not be fetched, the regime reads Unknown: we name the missing
reading, list no regime actions, and fill nothing in with an assumed value.
Canadian tax words you need
- Capital gain, 50% inclusion — if you sell something for more than you paid in a
taxable account, half of the profit is added to your income and taxed. Selling a winner
is therefore a real, immediate cost — not free.
- ACB (adjusted cost base) — your true average cost per share, used to work out the gain.
- Registered vs. taxable accounts — inside a TFSA, RRSP, or FHSA, gains aren’t taxed as
you trade; in a non-registered/joint account they are. So we prefer to do any necessary trimming
inside registered accounts first.
- US dividend withholding (15%) & the treaty — the US withholds 15% of dividends paid
to Canadians — except in an RRSP/RRIF, where the Canada-US treaty waives it. In a TFSA or
FHSA the 15% is simply lost (the treaty covers retirement plans only, not the TFSA or FHSA); in a
taxable account you can usually recover it via the foreign tax credit.
- Tax-loss harvesting & the superficial-loss rule — deliberately selling a loser to
offset gains — but if you, your spouse, or one of your own registered accounts buys the identical
security in the 30 days before or the 30 days after the sale, the CRA denies the
loss (the “superficial loss” rule). The safe move is to wait a full 30 clear days before rebuying.
A few more terms you’ll meet
- Beta — how much a stock tends to move relative to the whole market. Beta 1 moves with the
market; above 1 is more volatile (amplifies both up and down); below 1 is steadier.
- Sequence-of-returns risk — the danger that a big loss arrives at the worst possible time —
right before or early in retirement, or just before a goal — when there’s little time left to
recover. The same average return can hurt far more if the bad years come first.
- Dispersion / confidence — how much our valuation models disagree with each other.
Tight agreement = high confidence; wide disagreement = we say “unsure” instead of guessing.
In plain terms
Think of the Deep Score as a health score for a company and fair value as a fair price
tag with a margin of error. Concentration is “too many eggs in one basket,” counted across all
your baskets at once. The regime is the weather forecast. And remember: selling in a regular
(non-registered) account triggers a tax bill, so it’s never “free.”
01
System architecture & data flow
A single generation pass executes a deterministic pipeline; the LLM is invoked once,
late, with a fully-resolved context object.
- Ingestion & enrichment. Holdings are joined to live prices, the latest fundamentals
snapshot, account-type registry (capital-gains treatment, US-withholding flags), and the
investor profile / IPS inputs. Per-lot FX conversion yields both
price_native and
price_cad; aggregate single-name weights are computed across accounts.
- Quality & valuation. Each name carries a fundamental Deep Score and an
ensemble fair-value point + range + confidence tier (§3–4).
- Signal engine. ~28 deterministic rules evaluate every holding, emitting typed signals
with strength scores; de-duplicated and precedence-ranked (§7). Concentration ceilings are
tightened in hostile regimes (§8).
- Portfolio analytics. Concentration (single-name, GICS sector, industry cluster,
currency), beta-adjusted drawdown stress tests, and contribution-aware goal solve (§8–7, §11).
- LLM narration. The resolved context (slimmed holdings, concentration block, macro,
grouped signals, goal, profile, engine flags) is passed to the model, which returns structured
JSON: verdict, ranked priority actions, diversifiers, simulation, scenario notes (§15).
- Post-processing & render. Engine post-checks (look-through fund overlap; backfill of
the contribution-dependency note) run on the model output; the designed multi-page artifact is
assembled and served as printable HTML/PDF.
In plain terms
It works like a medical check-up. First a nurse gathers your vitals (your holdings, prices, scores).
Then lab machines take objective measurements (the rule engine). Then a doctor reads the results and
writes the report in plain English (the AI) — but the doctor follows strict protocols and can’t make
up a lab value. Finally the results are printed nicely (the designed PDF).
Generation-time vs render-time
Quantitative verdicts and narrative are baked at generation and persisted. Re-opening a
saved report re-runs only the presentation layer; reflecting new prices or a rule change requires
regeneration. Reproducibility: identical inputs → identical engine output (the LLM layer is
the only stochastic component, and it is constrained to narration).
02
Data sources & inputs
| Domain | Source & treatment |
| Prices | US equities via Alpaca (IEX feed) with a yfinance fallback; daily OHLC persisted to a local cache for trailing-return / volatility / moving-average computation. |
| Fundamentals | US deep-score inputs sourced from SEC EDGAR (10-year filings) with yfinance fallback for info/foreign filers; normalized earnings used to dampen cyclic peak/trough distortion. |
| Macro | BoC & Fed policy rates, CA/US 10Y, CAD/USD, WTI, CPI, VIX; plus an LLM web-search track for sector tailwind/headwind classification and Canadian headlines. |
| Trajectory metrics | ma_200, 52-week high, 3-year price anchors, trailing return_3m/6m, and a realized-volatility ratio (recent 21-day ÷ trailing 252-day). |
| KYC / IPS | Risk tolerance, objective, age & horizon, retirement year, DB-pension & net-worth context, emergency-fund & near-term-needs liquidity, max-drawdown tolerance, max single-position limit, exclusions, convictions, annual contribution. |
| History (for validation) | Every scheduled scan appends a dated snapshot per ticker (Deep Score, label, fair value, close price) keyed on (date, ticker). This accruing history is what the forward track record (§14) reads — it is never overwritten. |
03
Fundamental quality — the Deep Score
A 0–100 composite of profitability, balance-sheet, growth-durability and
capital-efficiency factors, descended from a 16-point value-investing checklist. It is deliberately
price-blind — it grades the business, not the security — so valuation and momentum
can sharpen it without contaminating it.
| Band | Interpretation | Engine consequence |
≥ 85 | Exceptional compounder | Eligible for ADD at a discount; HOLD when richly valued |
70–84 | High quality | Core long-hold; valuation governs entry, not exit |
55–69 | Acceptable | HOLD/neutral; valuation-trim only below 55 |
40–54 | Middling | Eligible for valuation-driven TRIM when rich |
< 40 | Avoid | SELL / TRIM regardless of account; never ADD |
In plain terms
One number, 0–100, for “how good is this company?” — like a credit score for a business. 85+ is
blue-chip; under 40 means the business is too weak to own. It ignores the share price on purpose: a
great company is still great on a day the stock falls.
04
Winner Odds — the durable-compounder ranker
A cross-sectional rank of the entire universe on the traits that recurred in history’s long-run compounders. Where the Deep Score grades quality today, Winner Odds asks which names have the makings of a business that keeps compounding and does not fail — and answers with a rank and a tier, never a probability. It is not a multi-bagger finder: on the point-in-time population test, top-tier names rose fourfold in five years about as often as any other name.
The factor set
Eight curated factors in two families, ranked against every other name using the same peer-relative robust-z statistics core as the Deep Score:
- Core quality — return on invested capital, gross profit over assets (Novy-Marx), the nine-signal Piotroski F-score, low accruals (Sloan), and margin stability.
- Core growth — growth acceleration, the Rule of 40, and reinvestment runway.
Value and momentum are computed as a side overlay only — never blended into the quality-and-growth rank, so a name cannot climb on cheapness or price action alone.
Percentile → tier, with hard gates
| Tier | Universe percentile |
| Strong candidate | ≥ 75th (the top quartile; the 90th-percentile cut was removed 2026-09-28) |
| Watch | ≥ 50th |
| Unlikely | below the median |
Two hard gates override the tier regardless of the factor score: financial distress (a weak Altman-Z) caps a name at Unlikely, and a cyclical business at a likely earnings peak caps it at Watch.
Rank-only — the honesty gateA simulated point-in-time test of every US 10-K filer FY2009–2022 (scripts/backtest_winner_population.py, judged by the one certification rule) certified the ordering (model register: winner 1.12.0 / 1.16.0), and still certifies it on the 2026-10-06 re-run under a repaired history (rank correlation 0.234, t 4.52; winner 1.16.1). A calibrated probability failed its held-out test, so the model is flagged CALIBRATED=False and never emits a win-%. A fabricated 68% would be worse than an honest rank.
In plain termsA scout’s shortlist: it lines up companies by how much they look like tomorrow’s giants and sorts them into tiers — but refuses to quote odds it can’t stand behind. winner_engine.py; the rank is tested on the point-in-time population, and the earlier in-sample run on a small hand-picked basket (backtest_winner.py) is superseded.
05
Emerging Compounders — the Inflection engine
A forward-looking companion to the Deep Score. It reads the rate of change — is the business getting better, faster — to catch businesses that are turning a corner before the trailing averages the Deep Score relies on can show it.
The inflection signals (engine 3.0.0, 2026-09-28)
Eleven signals, each measured as a trend (recent vs. earlier), not a level. Six carry weight: each is the name’s percentile among its sector peers that night, and the score is the weight-averaged percentile, re-based to the published bands. The weights are each signal’s measured rank correlation with the three-year outcome on every US 10-K filer FY2009–2022, scaled to sum to 100. The other five are shown as facts with no weight.
| Signal | Weight | What it catches |
| Share dilution | 28 | Share-count discipline — a rising share count ranks low |
| Margin expansion | 23 | Gross / net margins widening as it scales |
| Operating leverage | 14 | Profit climbing faster than sales |
| Improving returns | 13 | ROIC trending up, not merely already high |
| Earnings surprise | 12 | Quarterly earnings against the same quarter a year earlier, scaled by how much that change usually varies (from the company’s own filings) |
| Cash-flow inflection | 10 | Free cash flow turning positive or its margin rising |
| Growth acceleration | 0 (shown, no weight) | Revenue growing faster than a year or two ago — no lift on the population test, and the worst outcomes at its top rung |
| Early price breakout | 0 (shown, no weight) | The market starting to notice — no point-in-time history to test it |
| Insider buying | 0 (shown, no weight) | On the population test, insiders net buying preceded worse outcomes than net selling |
| Forward growth | 0 (shown, no weight) | Next-year analyst-consensus growth — no point-in-time history to test it |
| Estimate revisions | 0 (shown, no weight) | Which way analysts are moving their forecasts — no point-in-time history to test it |
Guards
- Cyclicality guard — commodity / cyclical names whose “acceleration” is just the up-leg of a cycle are capped at 50, so a rebound isn’t mistaken for a structural inflection. Heavy dilution caps a name at 50 the same way.
- Confidence band — names with less financial history score fewer signals; the band discloses how much data stood behind the number, and fewer than four of the six weighted signals gets no number at all.
Not certified on the re-run — and what that does and does not meanOn a simulated point-in-time test of every US 10-K filer FY2009–2022, run through the same certification rule Winner Odds passes, the 3.0.0 score certified as a rank on 28 September 2026 (rank correlation 0.169). It is not certified on the 2026-10-06 re-run under a corrected history (deflated Sharpe 0.48 vs 0.95 required); its ranks still separate (rank correlation 0.16, t 7.43, five independent windows; model register: inflection). The weights were measured on those same years, so the figures are in-sample for the weights. It separates failures better than it finds big winners, and it is not a forecast for any one company. An inflection is a possibility, not a prediction.
In plain termsThe Deep Score is a rear-view mirror of proven quality; this is the windshield. A mature giant with high-but-flat numbers scores near zero here even with a great Deep Score — and that disagreement is the whole point. inflection.py; tested on the point-in-time population by scripts/inflection_program.py (variant V7).
06
The fair-value ensemble
Intrinsic value is estimated by a multi-model ensemble (two DCF
variants, EV/EBITDA, Graham-style, dividend models, etc.), blended with dispersion-aware confidence.
The output is a point estimate, a low–high range, a coefficient-of-variation, and a confidence
tier — never a single fake-precise figure.
- Applicability filter. Keep models with a positive fair value applicable to the sector
(e.g. exclude FCF/EBITDA constructs for financials via sector policy).
- Price-anchored sanity gate. Drop any model outside
[0.33× , 3×] of the
current price — these reflect broken inputs (e.g. a normal multiple on peak-cycle EPS).
- Median outlier trim. Drop values outside
[0.40× , 2.50×] of the median.
- Family reduction. Average within each model family → one representative per family
(prevents a single methodology from dominating).
- Blend & dispersion. Point = mean of family representatives; range = their min/max;
dispersion = coefficient of variation (how widely the models disagree, σ/μ).
- Confidence tiering.
CoV < 0.15 → HIGH, < 0.30 → MEDIUM,
< 0.50 → LOW, > 0.50 → NOISE (suppressed — no trustworthy estimate;
caller skips the name rather than print a fantasy number). Requires ≥ 2 corroborating families.
Decision rule — “expensive” means something
Classification uses the range edges, not the point: a price below range_low is
a genuine discount, above range_high genuinely rich, and within the band is
fairly valued. Units are reconciled explicitly — the range is converted to CAD for the rules (vs
price_cad) and passed in native currency to the LLM to prevent cross-currency
mislabelling.
In plain terms
Instead of trusting one valuation formula, we run several and combine them — like getting several
appraisals on a house and reporting a price range with a confidence note rather than one
suspiciously exact figure. If the appraisals wildly disagree, we say “we don’t know” instead of
guessing.
07
The signal engine — taxonomy & triggers
Rules evaluate per holding and emit typed signals with 0–100 strength. Precedence:
SELL / ROTATE (exits) → TRIM → HOLD → ADD; TAX fires independently. De-duplication keeps the strongest
signal per (ticker, account, type); a TRIM rounding to < 1 share is suppressed as a no-op.
| Type | Rule | Trigger (deterministic) |
| SELL | avoid_fundamental | Deep Score < 40 |
| SELL | low_score_high_gain | score < 35 & gain > 25% (price ahead of quality) |
| SELL | dead_money | gain < −20% & score < 40 |
| SELL | dangerous_leverage | D/E > 3.0 & score < 45 |
| SELL | shrinking_revenue | 5-yr revenue CAGR < −3% (structural decline) |
| SELL | sector_headwind_weak | sector macro headwind & score < 42 |
| SELL | recession_risk_highbeta | contraction regime & β > 1.2 & whole-position weight > 3% & cyclical & score < 55 |
| ROTATE | growth_momentum_rotate | growth-sleeve name & momentum “broken” (below 200-DMA) — opt-in only; never a core holding |
| CRASH WATCH | crash_risk_protect | score ≥ 55, prior winner, agg weight > 5%, drawdown ≤ −20% from 52-wk high AND a confirmation (below 200-DMA OR return_3m ≤ −15% OR vol-ratio ≥ 1.5) → ~25% protective trim |
| TRIM | concentration_overweight | aggregate single-name weight > ceiling (max_single_position_pct or 25%) → trim toward ~70% of ceiling (25% → 18%) |
| TRIM REGIME | sector_overconcentration | GICS sector > ceiling → trim contributors toward ~80% of slice. Ceiling = 45% normally, tightened to 40% in late-cycle and 38% in contraction (§8). A sector limit the client declares replaces it, tighter or looser, and the regime does not tighten a declared limit; ADDs stop 5 points below it. Between the house 45% and a looser declared limit the rule stands down, and concentration_departures lists the sector (and any single name above 25% within a looser declared single-name limit) with a statement of the weight and both limits, printed in the report — the departure is recorded, not silent (CFA III(C)). |
| TRIM | moderate_overvaluation | score 40–54 & price above range_high (rich) |
| TRIM | mid_quality_overweight | score 38–55 & whole-position weight > 8% → the whole position to 5%, the same share off every account's slice |
| TRIM REGIME | usd_overexposure | portfolio USD > ceiling (45%, tightened to 40%/38% in late-cycle/contraction) & USD name & CAD stable/strengthening — registered only (suppressed on taxable winners) |
| TRIM | late_cycle_trim | late-cycle regime & β > 1.3 & whole-position weight > 4% & gain > 8% → ~33% |
| TRIM | deteriorating_outlook_trim | outlook_pressure ≤ −0.35, heading late-cycle/contraction, med/high confidence, β > 1.2, whole-position weight > 4%, gain > 5% → ~25% |
| TRIM | downtrend_value_trap | multi-year downtrend (near 3-yr low) & score < 55 |
| HOLD | quality_richly_valued | score ≥ 55 & price above range_high — the cardinal-rule verdict |
| ADD | quality_at_discount | score ≥ 70 & price below range_low (not in a downtrend) |
| ADD | fair_value_entry | score ≥ 65 & price within the range |
| ADD | underweight_winner / low_weight_high_conviction / sector_tailwind / recovery_add / cad_weakness_usd | various under-sized high-quality adds, “under-sized” meaning the whole position across accounts — all gated by an overweight-sector guard (sector < 40%) and by the name's ADD level: no ADD once the whole position reaches the single-name limit × 40/45 (≈22.2% at 25%) |
| TAX | tax_loss_harvest | taxable account, loss < −8% & < −C$1,000 → harvest; observe the superficial-loss window — no identical-security purchase by the investor or an affiliated person in the 30 days before or after (ITA s.54 / s.40(2)(g)) |
| TAX | migrate_to_rrsp | USD payer, yield > 1.5%, withholding applies → relocate to RRSP (treaty Art. XXI); flags the deemed-disposition cost of an in-kind move |
In plain terms
A fixed checklist runs against every holding and produces a colour-coded suggestion: red SELL (only
when a business is genuinely deteriorating), amber TRIM (lighten, don’t exit), blue HOLD (keep, don’t
add), green ADD (build a good, under-owned position), and a tax housekeeping flag. It runs the same
way every time — no mood, no hunches.
08
Risk framework — concentration, regime & drawdown
NEW The allocation policy, and the trade a breach implies
Where a client has declared an investment policy (target weights for equity, fixed income and cash,
plus a drift band), that policy is the first lens and a breach is the first action in the plan — ahead
of any single-name idea, enforced by the engine after the narrative is written rather than requested of
the model.
When a breach has already been shown, the report asks about the policy. CFA Standard III(C) says an investment policy is reviewed at least annually, and a client holding an off-policy book is discussed with: the trade is made or the policy updated. The report asks that question when the book was outside the same policy, in the same class and direction, in the report before (and every report back to the first such one), and the policy has not been saved since; or when the policy was last saved more than 365 days ago. Re-saving the policy restarts the clock. A report inside the band, or one whose lens failed, ends the chain. An unknown save date triggers nothing. The question never proposes moving the policy to match the book.
A declared cash reserve is outside the policy. Liquidity needs are the first constraint a policy is written under (CFA Standard III(C)). The client declares a reserve in dollars; the mix removes min(reserve, cash) from the cash class and from the base every percentage is a share of, so drift, the policy trade and the contribution plan are computed on deployable money only. A reserve larger than the cash on file is reported as a shortfall and is never made up from a GIC or a holding; new contributions rebuild it first. With no reserve declared the value is unknown, not zero: no number moves, and where a cash-over breach draws on savings the client entered, the report states how much of the cash that is and asks. The reserve is never inferred from an item's name or from months of expenses.
- Every breached class, not only the largest — the over-weighted class and the under-weighted
one are a single trade. Naming only the bigger side leaves half an instruction: a book 24pp
over in cash and 20pp under in fixed income was previously told “reduce cash toward 5%”, and the
destination was the second breach.
- In dollars, and the legs balance — every class moves to the target the client declared, so
what is added equals what is reduced by construction. A class inside its band still appears,
because it is where money comes from or goes; a rebalance naming only breached classes does not add up.
- The funding source, because it decides the cost — money moved out of cash is not a
disposition and realises nothing; selling equity or bonds realises a gain or loss in a non-registered
account. The split is reported, and new contributions are offered first because they move the mix
without a sale.
- The tax itself is not estimated. It depends on which lots in which accounts are sold, and the
trade builder is handed neither — so it reports how much requires a disposition and stops there rather
than publishing a plausible figure.
- Unclassified money is named, never absorbed — holdings the look-through cannot split into an
asset class are excluded from the trade and disclosed, so the class figures are not quietly inflated.
A practice considered and declined. Vanguard’s threshold-rebalancing rule — trigger at 200bp of
drift and rebalance to 175bp rather than to target — was evaluated and not adopted. It is
derived on target-date funds rebalanced at scale, where the question is when to trim a portfolio that is
already near its targets. That precondition does not hold here: the declared bands are around 5pp
and measured breaches run 20–25pp, four to five times outside them, so a better trigger would change
nothing on any live book. What was missing was not a smarter threshold but an actionable trade. Every leg
therefore targets the policy the client declared, not a band edge.
Concentration (the first lens)
- Single-name — measured on the aggregated weight across accounts (the same issuer in
a TFSA and an RRSP is one position); honours a client-specified
max_single_position_pct,
else a 25% ceiling, trimming toward ~70% of the ceiling (18% at 25%).
- Sector & industry — a GICS sector ceiling (see regime-aware tightening below); a finer
industry cluster lens (e.g. semiconductors as one cyclical complex) is surfaced because it
is often the real risk even when the “Technology” sector merely looks large.
- Currency — a USD-exposure ceiling; trimming is registered-account-only and never applied
to a taxable winner for a soft FX reason.
NEW Regime-aware concentration ceilings
Concentration hurts more when markets are fragile, because in a downturn correlated names fall
together. So the sector and currency ceilings are now a function of the market regime rather
than fixed:
| Regime | Sector / USD ceiling | Rationale |
| Expansion / Recovery | 45% (unchanged) | Benign — the normal ceiling applies. |
| Late-cycle | 40% (−5) | Getting toppy — start easing concentration a notch sooner. |
| Contraction | 38% (−7) | Stress — correlated bets are the danger; nudge harder. |
The tightening is deliberately modest (≤7 points) and the rationale string names
the regime and the active ceiling, so it is transparent. When the macro feed is unavailable, the
ceiling falls back to the base 45% — missing data can never tighten anything.
Why this does NOT violate the cardinal rule
This applies only to sector and currency rebalancing — legitimate risk management — never to
the cardinal rule that a quality single name is never sold on price or macro alone. It changes a
rebalancing threshold, not the no-panic-sell discipline; every signal is still a suggestion
the investor chooses to act on. On the procyclicality risk — tightening a ceiling during a contraction
could imply trimming an already-depressed sector — the mitigants are deliberate: the move is small
(≤7 pts), it is a suggestion the investor may decline, and it is funded registered-account-first to
avoid crystallising a taxable loss. It is a risk-budget guardrail, not a market-timing trade. We also
rejected a full dynamic correlation matrix on purpose (§16).
Drawdown & horizon
- Beta-adjusted stress tests — dollar-denominated downside under semiconductor-downcycle,
broad-bear and severe-recession scenarios, framed against the client’s stated max-drawdown tolerance.
Each holding falls by its own beta (a CIBC CDR by its US company’s); a holding with no beta on file
is left out and named, never given one, and the book’s value after a market-wide fall is then not
stated (the Goal Risk line then says the shortfall cannot be stated).
With no beta anywhere nothing can be modelled, and the rows state no loss and no value after.
- Dual horizon — the engine reconciles risk capacity from the retirement horizon
with the nearest funded goal: where a major drawdown landing near the goal year would cause a
shortfall, it surfaces an explicit Goal Risk and a light glide-path — without forcing the
whole book conservative. Sequence-of-returns risk dominates inside ~7 years.
- Deterioration sells fire BEFORE price — note that several SELL rules (dangerous leverage,
shrinking revenue, an AVOID-rated score the business itself confirms) trigger on the business deteriorating, independent
of any price drawdown. The 20%-drawdown “Crash Watch” (§9) is a separate, last-line protective
trim, not the only defence.
In plain terms
Don’t let any one stock, industry, or currency get too big — and when the weather turns stormy, trim
the “too big” line a little sooner. It’s like tightening your seatbelt when the road gets icy. This is
about baskets of eggs, never about dumping a great company because the market dipped.
09
The cardinal rule & the trend-rollover overlay
The governing policy — chosen for an after-tax, buy-and-hold personal book —
is that valuation alone does not trigger a SELL of a quality compounder: a rich price
routes to HOLD (stop adding), preserving compounding and avoiding a realised capital gain. SELL is
reserved for genuine deterioration (§7). Extreme valuation is handled not by a valuation-SELL but by the
concentration ceiling (no name runs unbounded as a share of the book, §8) and the
goal-return lens (which can redeploy on forward-return grounds, §11). We accept the trade-off
openly: a pure valuation discipline would occasionally sell a very expensive great business; we weigh
that against tax friction and the cost of interrupting compounding.
The single sanctioned price-driven protective action is the crash-risk overlay: the
engine does not trim a winner for being up or richly valued, but when a quality holding has
rolled over — drawdown ≤ −20% from its 52-week high plus a confirmed trend break
(sub-200-DMA, a sharp 3-month decline, or a realized-volatility expansion) — it raises a “Crash Watch”
and proposes a ~25% protective trim or a stop, the client’s discretion. Sizing is
tax-tiered (realise in registered first; quantify the gain in non-registered). A normal pullback with
the trend intact is tolerated and produces no signal.
Honest limitation — and why it’s acceptable
A trend-confirmation overlay is, by construction, late: it cedes the tolerated ~20–25% drawdown before
acting, protecting the remainder. This is the deliberate trade-off of “let winners run” versus trimming
early at the top. But it is not the portfolio’s only protection — fundamental-deterioration
SELLs (§7, §8) act ahead of price when the business, not just the chart, is breaking.
In plain terms
We never sell a great company just because its price went up. The only price-based caution is when a
former winner is clearly rolling over — down 20%+ from its high and breaking its trend — at
which point we suggest protecting about a quarter and letting the rest ride. A normal dip does nothing.
10
Canadian tax architecture
| Mechanism | Treatment encoded |
| US-dividend withholding | 15% treaty withholding applies in taxable, TFSA & FHSA; eliminated only in RRSP/RRIF/Spousal RRSP/LIRA/LIF (Art. XXI). In a taxable account it is recoverable via the foreign tax credit; in a TFSA or FHSA it is lost entirely (the treaty covers retirement plans, not the TFSA/FHSA). |
| Asset location | US-dividend payers preferred in RRSP; the engine prefers trimming in registered (tax-free) over realising a taxable gain when the choice exists. |
| Superficial loss | Loss-harvest signals embed the superficial-loss window — no purchase of the identical security by the investor or an affiliated person (spouse, your RRSP/TFSA, a controlled corporation) in the 30 days before or after the sale (ITA s.54 / s.40(2)(g)) — to avoid loss denial. |
| In-kind RRSP contribution | Flagged as a deemed disposition at FMV — accrued gain is realised (taxable), an accrued loss is denied — and it consumes contribution room; prefer funding with new contributions / low-gain lots. |
| FX as capital gain | CRA treats a gain on converting foreign currency (e.g. USD cash → CAD) as a capital gain — a separate event from the gain on the security, subject to a $200 annual de-minimis for individuals (ITA s.39(1.1)). Currency-matched deployment (USD cash → USD-listed) avoids triggering it (and an FX spread). |
| T1135 foreign-property reporting | Non-registered “specified foreign property” (e.g. US-listed equities) whose total cost exceeds C$100,000 at any point in the year triggers a T1135 filing obligation; registered accounts are excluded. Surfaced in the separate Tax & Structure Audit. |
| Capital-gains cost surfaced | Every SELL/TRIM in a taxable account carries the realised-gain estimate (50% inclusion) in its tax note, so the after-tax cost of acting is explicit. |
NEW Tax-neutral rebalancing — fund changes with new money first
The framework’s standing preference is to reach a target allocation without realising a
taxable gain wherever possible. Two mechanisms enforce this:
- Contributions as the primary de-risking lever — when the contribution stream can pull an
overweight industry to target within ~3 years, the engine computes that path and prefers directing
new cash over selling winners; it states the dependency (and a fallback floor if
contributions fall short). This logic predates this revision and lives in the Strategy report’s
action plan.
- Tax-Neutral Check in the manual Rebalance tool — when a rebalance plan would realise a
capital-gains tax, the preview now shows a Tax-Neutral Check: it quantifies the taxable
gain the plan triggers and, where the increases could instead be funded from idle cash or upcoming
contributions, says so explicitly — and confirms when the buys fit entirely within idle cash and
need no sale at all. The reflex becomes “add with new money before trimming a taxable winner.”
In plain terms
Rebalancing usually means selling some of what you have too much of and buying more of what you’re
light on — and selling can trigger a tax bill. So before suggesting a sale, the tool checks whether
your new contributions or spare cash could simply buy the under-weighted positions up to
target. Reaching balance by topping up, rather than selling, keeps the taxman out of it.
11
Macro regime, forward outlook & goal solve
Regime & probability-weighted outlook
Current regime is classified from the rate/cycle environment. A forward outlook ensemble —
yield-curve slope (10Y–2Y), HY credit-spread trajectory, index vs 200-DMA, VIX trend, and CPI direction —
produces an outlook_pressure, a heading (late-cycle / contraction), a transition probability
and a confidence. Deteriorating readings bias defensive timing toward act-now / within-30-days,
and (per §8) tighten concentration ceilings. This is a probability-weighted regime trajectory,
not a price or index-level forecast.
Goal-based framing
- Contribution-aware required return — the required CAGR is solved (binary search) including a
level annual contribution, since the balance-only figure materially overstates difficulty when
contributions are large;
on-track is benchmarked at ≤ 8%.
- Goal-return lens — idle cash and any holding whose realistic forward return sits below the
required rate are framed as opportunity-cost drags — candidates to redeploy into higher-expected-return
diversifiers (tax-aware), not a reason to sell a quality compounder.
In plain terms
We read the market “weather” and which way it’s trending — never a price prediction — and we always
measure your plan against your goal: the yearly return you need, counting your contributions,
to get there on time.
12
Portfolio construction & diversifier logic
- Objective-aware — growth / aggressive or 12+ yr horizon keeps a growth tilt (quality
compounders in different growth industries; broad/growth funds), explicitly not
defensive sectors or bonds; income / capital-preservation / < 7 yr tilts to dividend, low-beta,
broad-market or fixed income.
- Grounded single-name candidates — sourced from the client’s own scored universe via a GARP
screen (deep-score ≥ 70, D/E < 1.0, ROE ≥ 15%, earnings/revenue CAGR ≥ 12%, valuation gate), with
multi-year downtrends and currently-held names excluded; the LLM may not invent a ticker.
- Phase-in vs deploy-now — each candidate carries an engine-decided
deploy_mode:
at/below fair value → deploy idle cash; above fair value → accumulate via contributions / on a
pullback toward the 200-DMA.
- Currency-matched — deploy each account’s idle cash in its own currency to avoid an FX spread
and a taxable conversion event.
- Look-through overlap — a recommended broad fund is checked against the client’s overweight
names; material single-name/mega-cap overlap is disclosed rather than silently recommended.
- NEW Where the next contribution goes — for a client
still saving, what they are about to add outweighs what they hold. The report splits the
annual contribution across asset classes in dollars: after a contribution the book is its
present value plus that amount, each class’s target is its policy weight times that, and the
contribution is shared in proportion to each class’s shortfall. A class already above its
target receives nothing; nothing is sold; growth is ignored, so every horizon is
conservative and no return is assumed. Where a year of contributions reaches the policy the
report says so beside the rebalancing trade; where it would take longer it says how many
years. It also states what the contribution does to a concentrated sector. It needs a
declared policy, and it does not say which account the money goes into.
- NEW Funds are screened and measured, not recalled — a
recommended fund comes from the scanned fund universe, never from the model’s memory. To be
offered it must carry known sector weights, classify as equity, sit in the fund score’s top
tier, and hold no more than 40% in any one sector — the same threshold at which this report
calls a client’s own book concentrated. Funds are ranked by their weight in the client’s
overweight sector, and each recommendation states that weight and what the book’s sector weight
becomes if new money equal to a tenth of the book goes into the fund. That is arithmetic on
holdings, not a forecast of return. Where a sector exceeds 40% of the book and the
recommendations name no screened fund, the engine places the first one at the top of the list,
with no position size. The quality floor inherits the fund score’s trailing-return component,
so it leans toward funds that have done well; sector weights are on file for 182 of 245 scanned
funds, and the other 63 cannot be offered.
- NEW What “diversifies” rests on — the screen selects candidates
outside the client’s overweight sectors, and until now the word “diversifies” stood on that
alone: the candidate record carries ticker, name, sector, Deep Score, the growth-pillar fields and
valuation fields, and nothing about how the name moves with the book. A different sector is a
real basis and a weak one — two GICS sectors can move together closely, which is precisely why the
Risk X-Ray measures effective bets rather than counting names. Each single name now states
that basis, and where price history allows it carries the measured change in effective bets,
computed through the same
risk_data / risk_concentration pair the X-Ray uses
so the two cannot disagree about one book. Coverage is a minority and is named as such: measured on
2026-09-24, 4 of 10 live candidates carry the ≥60 days of history a correlation needs, and the
other six read NOT measured rather than staying silent — silence beside a diversification
claim reads as assent. A candidate that measurably does not diversify is disclosed as such,
with the recommendation left standing and the contradiction stated beside it.
- NEW The screen can suspend itself — if graded cohorts persistently
underperform (three, a recorded decision rather than a fitted number), the report stops recommending
single names entirely and reverts to allocation-level advice; ETF recommendations continue, because
allocation rests on a declared policy, a tax rule and an arithmetic identity and is not what failed.
The rule cannot fire yet — the grader is network-bound and not in CI, so no cohort verdict is
stored where the report can read one — and it returns a state with its basis
(“no graded cohort yet”) rather than a boolean, because “not suspended” and “not yet judgeable” are
different facts and a boolean collapses them into the reassuring one.
- NEW A single name is research, never sized — an individual company
arrives labelled Research with no suggested position size, and states how much graded
forward evidence stands behind the screen. A size is the sentence that turns research into advice:
“consider this name” and “put 3–5% into this name” are different acts, and the second implies a basis
this screen does not have — no pick has a graded forward return yet. Measured before the change:
180 of 180 single-name recommendations across 48 stored reports carried a weight. An ETF keeps
its weight, because an allocation decision rests on the client’s declared policy, a tax rule or an
arithmetic identity. Stripped at the engine choke point rather than requested of the model (the prompt
already asked and produced 180 of 180 the other way), and guarded in both renderers so reports written
earlier stop showing a size too.
- NEW Growth-pillar dependence, disclosed by the engine — where a
recommended single name owes more of its Deep Score to the Growth pillar than an evenly-scoring
name would — above the pillar’s own weight share of 25 of 100 points — that share is stated in the
recommendation itself. Both of the pillar’s inputs (
revenue_growth, earnings_growth)
are historical, and the literature is against extrapolating them: Chan, Karceski & Lakonishok
(Journal of Finance, 2003) find no persistence in long-term earnings growth beyond chance, and
Lakonishok, Shleifer & Vishny (Journal of Finance, 1994) find the fastest-growing names
underperform over five years. Measured on the 2026-09-24 production scan of 2,577 scored names: the rank
correlation between the shipped score and the score with the pillar removed is 0.97, yet 45 of the top 50
names are in that set only because of it, and 6 of the 8 names the live screen surfaced were
Growth-lifted (mean 20.6 of 25 against a universe mean of 12.5). The pillar is disclosed, not
re-weighted — whether its sign is wrong on this book is not testable yet. The
price-history gap that used to be the reason is closed (2,786 of 2,792 scored names; 988 of the 1,059
scored on 8 June 2026), so what remains is time — that group's 126-day window closes 12 October 2026,
and until it is graded, re-weighting on the literature alone would trade one unvalidated prior for another. The note says screen, not forecast: no
forward claim is made, because none has been validated (CFA Standard V.A).
- NEW Single-name concentration, stated against a budget — the share
of the book held as individual securities rather than funds, measured by value and shown whenever
it exceeds the 20% default budget, with its basis: only 42.6% of roughly 26,000 US stocks since 1926 beat
one-month Treasury bills over their lifetime and the best 4% of firms account for all net wealth creation
(Bessembinder, Journal of Financial Economics, 2018), and removing 90% of diversifiable risk takes
40–50 names rather than 15–20 (Statman 1987; Domian, Louton & Racine 2007). Disclosed, not
enforced — no trade is blocked and no plan rejected for exceeding it. Measured 2026-09-24: all six live
books exceed it, from 62.9% to 100.0%.
- The engine writes these, not the model — both notes are appended after the narrative has been
written, at one choke point (
_apply_engine_disclosures). A field placed in a prompt is a
request; the model writes its own reasons and is free to leave the inconvenient half out. Neither pass
changes a score, a rank, a pick or a position size.
- Contributions as the primary de-risking lever — see §10; directing new cash is preferred to
realising gains, with a computed dependency and fallback floor.
13
NEW Conviction override & the documented-thesis audit trail
The best frameworks make room for genuine human knowledge without letting it
quietly corrupt a deterministic engine. The conviction override is that bridge.
- Structured override — on any holding, the investor can overrule the engine’s recommendation
(set it to ADD / HOLD / TRIM / SELL). The engine’s own verdict always remains visible beside the
override, so the disagreement is explicit, never hidden.
- Documentation is compelled on a contrarian call — when the override softens a
protective verdict — the engine said SELL or TRIM and the investor overrides to HOLD or ADD —
the system blocks the save until a written thesis is entered (“why, and what would
prove you wrong?”). Agreeing with the engine, going more cautious, or clearing the override needs no
thesis. So conviction is allowed, but never undocumented.
- Append-only audit trail — every change is written to a conviction log — a dated,
append-only history showing the stance change (e.g.
Auto → ADD) and the thesis. Nothing
is overwritten; the record of why a position was held against the engine survives for later
review. This mirrors the Sector Lab conviction journal already used for sector theses.
Scope — deliberately documentation, not behaviour
The override records and surfaces human conviction; it does not silently rewire the signal
engine. The engine stays deterministic and reproducible; the human decision sits beside it, on the
record, with its reasoning attached. This is how “soft” knowledge enters without introducing model bias.
In plain terms
Suppose the engine says “trim this” but you have real conviction — you know something, or you’re a
long-term believer. You’re allowed to overrule it. But if you’re overruling a caution, you must first
type why (and what would change your mind). That note is saved with a date forever, so future-you can
honestly check whether the call was wise. Discipline and conviction, both on the record.
14
NEW Validation & the forward grade of its own calls
A good framework keeps score of itself — honestly — so its parameters can be improved
by human judgement over time. It does not secretly rewrite its own weights.
What is measured
- Fair-value accuracy — stored fair values are graded forward against the realized price weeks
later: a directional hit-rate (did the under/overvalued call match the later move?) and a median
absolute % error, broken out by confidence tier and sector.
- Verdict forward grade — because every scheduled scan appends a dated snapshot of each
name’s quality verdict (STRONG BUY … AVOID), the engine can grade its own calls as they
age: for each verdict it measures the realized forward return ~6 and ~12 months later, bucketed by
band, and checks the basic monotonicity that STRONG BUY/BUY should beat AVOID. The report states how
many name-dates had enough forward history, so coverage is never silently overstated. This
is a forward grade, not a back-test, and nothing has been graded yet: no cohort has
matured (the first reaches 126 days on 2026-10-12), so no hit rate is published and the labels
have not been tested against returns. It reads stored closing prices, which a split or a delisting
between scans can distort. A separate point-in-time population test (2026-10-06, US filers
FY2009–2022) found the Deep Score’s fundamentals ranked later peer-relative returns modestly well;
its label cut-offs, valuation inputs and the sizing bands were not tested. Even when graded, this measures signal accuracy on accrued history — not the
investor’s realized portfolio return.
PRINCIPLE Measurement informs people — it never auto-tunes the engine
This track record is read by a human to decide whether to recalibrate — exactly as the sector
multiples and normalized-earnings model were deliberately re-tuned in June 2026. No code path
adjusts the Deep Score weights or fair-value parameters automatically from outcomes. We reject
self-tuning on principle (§16): on a single portfolio of a few dozen names over a couple of years it
would overfit noise, chase recent performance — the very behaviour value investing exists to resist —
and quietly convert a transparent, deterministic calculator into a self-modifying advice algorithm,
which is precisely the NI 31-103 line the product guards.
In plain terms
The engine is keeping a report card: of the stocks it rated “strong buy,” how did they actually do six and
twelve months later — and did they beat the ones it rated “avoid”? None of them is old enough to grade
yet, so the card is still blank. When it fills in, you (a human) read it and decide whether to adjust
the rules. The engine never silently rewrites itself to chase whatever worked
lately — that’s how systems fool themselves, and we won’t do it.
15
LLM governance, controls & reproducibility
- Constrained role — the model (Claude, structured-JSON output) validates signals,
ranks ~8 priority actions, adds timing/framework/tax narration and a simulation. It cannot fabricate a
price, fair value, SELL, or out-of-universe ticker.
- Flag demotion — deterministic decisions (deploy-mode, contribution-dependency, fund-overlap)
are computed in the engine and merely narrated, with engine-side backfill so a flag cannot be silently
dropped under prompt load.
- Audit trail — wherever the model’s final action differs from the deterministic rule signal for
a name, the override is disclosed with its rationale (“rule said TRIM → advisor chose HOLD: …”).
- Test & ops — the rule base and renderers are covered by an automated suite in which every
signal rule carries at least one threshold test; the data layer self-heals its schema across deploys;
the report degrades gracefully on missing inputs.
In plain terms
The AI is kept on a tight leash: it explains and prioritises, it doesn’t calculate. If it ever disagrees
with the rulebook, the report says so out loud. And thousands of automated tests guard the maths.
16
Design rationale — why it’s built this way
Common questions a reviewer asks, and the deliberate reasoning behind each answer.
- Why a semiconductor-cluster heuristic instead of a live correlation matrix?
- For a personal book of ~10–30 names, a rolling correlation matrix is fragile: correlations are
noisiest exactly when you would act on them (in a crash everything correlates toward 1), so it would
generate the most sell pressure at the worst time. The honest cluster heuristic (treating, e.g.,
semiconductors as one cyclical complex) captures the concentration that actually matters, and the new
regime-aware ceilings (§8) supply the “tighten when fragile” behaviour without the instability or the
false precision.
- Is the tax handling reactive or projective?
- Both, by design. Per-action tax consequences are reactive (they price the cost of a trade you’re
considering). But the plan is projective: contributions are modelled as the primary
de-risking lever, and the Rebalance tool’s Tax-Neutral Check (§10) steers you to reach targets with new
money before triggering a taxable disposition. Full contribution-room/placement projection lives in the
separate Tax & Structure Audit, so the Strategy report stays focused.
- How does human intuition enter without introducing model bias?
- Through the conviction override (§13): a structured, documented, append-only override that sits
beside the deterministic engine rather than inside it. The investor may overrule a rating, but
overruling a caution compels a written thesis, and every change is logged with a date. The engine stays
deterministic; the human judgement is explicit and on the record.
- The 20%-drawdown trigger is “late by design” — isn’t that dangerous?
- The Crash Watch is intentionally late because it protects a winner you want to keep after a
tolerated pullback — trimming early at every top would forfeit the compounding that is the whole point.
Crucially it is not the only defence: fundamental-deterioration SELLs (dangerous leverage, structural
revenue decline, an AVOID-rated score the business itself confirms — §7/§8) fire on the business breaking, ahead of price.
So catastrophic-failure protection comes from the fundamentals path; Crash Watch only guards a
still-good name whose chart has clearly rolled over.
- Why not let the engine self-optimise its weights from outcomes?
- Because a self-tuning loop on one small portfolio over a short history overfits noise and chases
recent performance — the opposite of disciplined value investing — and it would turn a transparent,
auditable calculator into an opaque, self-modifying advice algorithm (an NI 31-103 concern). We build
the measurement (§14) and let a human recalibrate deliberately, which is both safer and more honest.
17
Disclosures & methodological limitations
- Rules-based signals, not personalized advice. The report applies published rules to the
investor’s own inputs; its SELL/TRIM/HOLD/ADD outputs — some with a suggested share count — are
general information and starting points for the investor’s own judgement, not personalized advice
from a registered adviser. The investor makes every decision, and nothing executes automatically.
- No price/level forecasts. Forward statements are probability-weighted regime trajectories, never targets.
- Fair-value conservatism. The ensemble is conservative on steady non-mania names; the range +
confidence tier is the explicit mitigant against false precision, and NOISE-tier names are suppressed.
- Crash Watch is late by design. The trend-rollover overlay protects the residual after a tolerated
drawdown, not the peak; the fundamental-deterioration SELLs are the earlier line of defence.
- No company-news trigger. Confirmation is price-and-fundamentals based; idiosyncratic event risk
(earnings, litigation, M&A) is not modelled in the deterministic engine.
- Validation is measurement, not control. The track record informs human recalibration; it never
auto-tunes engine parameters.
- Data dependency. Outputs are only as current as the latest scan; the forward track record
accrues forward history over time and states its own coverage.
In one line
A disciplined quality-and-value philosophy, encoded as testable deterministic rules — now regime-aware,
tax-neutral by preference, open to documented human conviction, and honestly self-scored — anchored to the
client’s IPS, goal and Canadian tax position, and translated into account-level, currency-native actions by
a tightly-governed LLM exposition layer.