Add memory_supply_allocation template (multi-reasoner)#77
Conversation
…ed RCA, multi-reasoner) Four-reasoner chain on one ontology: Predictive (pre-computed supplier capability forecast) -> Rules (customer-customer dependency yield + elevated floor) -> Prescriptive (monthly rolling-horizon LP across 36 months with two disruption reveals) -> Graph (paths library for dependency-chain enumeration + RCA + two what-if scenarios). Demonstrates a planner workflow under structural scarcity: HBM3E demand exceeds capacity, and hyperscaler customers are willing to yield part of their allocation so the equipment-maker customers they depend on stay supplied. As disruptions surface (Orion Foundry downtime at month 5, helium shortage at month 13), the LP re-solves the remaining horizon; plan-diff between iterations exposes who absorbs each shock. - Stage 1 (Rules): max_declared_yield_pct, elevated_floor_pct, depends_on graph edge, is_dependency_spof flag, all ontology-resident. - Stage 2 (Predictive): SupplierCapabilityForecast loaded as a regression target per (supplier, month). Clean upgrade path to rai-predictive-modeling GNN node classification if richer features are available. - Stage 3 (Prescriptive): revenue-max LP with effective_capacity per (product, period) = sum_suppliers(nominal x capability_pct) x product of (1 - intensity x (1 - availability)) across raw-material inputs. 3-step rolling horizon with disruption reveals; fresh Problem per iteration with populate=False extraction. - Stage 4 (Graph / paths): model.path(Customer.depends_on.repeat(1, 3)) .all_paths() enumerates variable-length chains. Two what-if branches ablate one supplier and one input at a time, ranked by cascade footprint on (product, period) cells. Run output: - iter 0 baseline (months 1-36): OPTIMAL, \$47.09B margin - iter 1 Orion downtime revealed (months 5-36): OPTIMAL, \$41.96B; hyperscalers absorb the disruption, equipment-maker customers stay pinned at their elevated floors via the dependency mechanic - iter 2 helium shortage revealed (months 13-36): OPTIMAL, \$30.19B; hyperscalers absorb a further \$4.5B, equipment makers still protected - Apex Photonic Components flagged as the lone dependency-graph SPOF via ontology query; Orion Foundry has the widest supplier-offline impact; Helium has the widest input-shortage impact (180 affected cells)
…gy bindings
- Banner style: switch from `# ---- Stage N: ... ----` (single line) to the
box-comment format used by `telco_network_recovery.py` and
`energy_grid_planning.py`. Drop the "Stage 0" prefix from the ontology-load
section to match the reference template (no stage number for the load
block; stages 1-4 are the reasoner stages).
- Stage 4 ontology bindings: persist the what-if structural conclusions
back to the ontology so a post-hoc analyst can query supplier-offline
risk and input-shortage risk without re-running the pipeline:
Supplier.offline_impact_cells (Integer)
Supplier.offline_max_cap_drop_pct (Float)
Input.shortage_impact_cells (Integer)
Closes the "every reasoner stage binds output back to the ontology"
checklist gap.
- Remove unused HELIUM_INPUT_ID constant.
- Reorder + format display-only columns so printed output matches the
README expected-output block (max_cap_drop_% column appears between
n_affected_cells and affected_products, formatted as percentage).
No behavior changes to the LP, the paths analysis, or the disruption
mechanics. Run reproduces identical margins ($47.09B / $41.96B / $30.19B)
and identical Headline (Apex SPOF, Orion widest supplier impact, Helium
widest input impact, $16.9B margin erosion).
Ten-step walkthrough of the four-reasoner chain. Each step has a Prompt (skill-prefixed, question-shaped, with definitions inline and scope stated explicitly) and a Response block whose numbers match the script's actual print output. Sequential cascade: prompts inherit ontology state from earlier steps via property and concept names, never via step numbers. - Lead-in + chain ASCII: 11 customers / 5 SKUs / 36 months / 6 suppliers / 3 inputs; baseline $47.09B margin headline, 24-month-tail $30.19B, Apex SPOF, Orion widest supplier impact, Helium widest input impact. - Stages 1-4 each show: ontology enrichments written, row counts, and the business answer the named skill produces. - Numerical cohesion against the script: per-customer service levels (Hyperion 76%, Aether 83.7%, equipment makers 95-99%), iter 1/iter 2 margins ($41.96B / $30.19B), plan diffs (Aether -$369.62M / Hyperion -$280.36M at iter 1; Hyperion -$2,149.37M / Aether -$1,839.17M at iter 2), what-if cascade rankings (Orion 72 cells / 60.9% max; Helium 180 cells). Closes the multi-reasoner-templates-have-a-runbook gap flagged in the dev-templates-review pass.
Real paste-test against fresh /rai-* skill sessions verified the runbook against the bundled ontology + data; this commit applies the wording fixes the test surfaced. No script changes. What reproduced exactly: - Step 6 baseline LP margin: $47,089,150,341 to the dollar - Step 7 iter 1 margin: $41,960,554,872 exactly - Step 9 cascade rankings: Orion 72 cells / 60.9% max drop, Helium 180 cells / 35% HBM3E avg drop — bit-exact - Step 5 forecast stats and Step 4 SPOF flag (Apex Photonic) match What needed clarification: - Step 2 + chain ASCII: "4 customers declare yield" was wrong; Photonic Lithography is also a downstream yielder (to Apex) AND an upstream receiver (from Hyperion/Aether) -- the bridge node that creates both 2-hop chains. Now reported as 5 yielding customers with Photonic's dual role called out. - Step 4: rules-authoring response now explicitly states the coalesce-to-default requirement; sparse derived properties silently break downstream solver constraints (the symptom is alloc grossly exceeding demand, not INFEASIBLE), so this is worth flagging in the prompt response. - Step 6: per-customer service levels are LP-degenerate -- multiple optimal allocations exist on the feasible face with identical total margin. Response now hedges to representative ranges (hyperscalers 76-84%, equipment makers 95-99%) and leads with the invariant margin headline. - Step 7: input disruption semantics are persistent through end of horizon in the script (suppliers DO respect their window). Response now states this explicitly and notes that window-only helium semantics would yield iter 2 margin ~$31.94B instead. Iter 1 reproduced exactly; iter 2 has a documented dependency on this semantic choice. - Step 8: model.path(...).all_paths() requires explicit role short_names on the same-type two-slot relationship. Prompt now includes the exact declaration so the paths library can resolve the depends_on edge. New "Reproducibility notes" section at the end of the runbook collects these findings explicitly so future analysts know what's deterministic and what isn't. Forecast range corrected from [0.91, 0.99] to [0.93, 0.99] (the actual data range). Out of scope, surfaced as follow-ups: - rai-graph-analysis skill needs a paths-library section - Input vs supplier disruption-window asymmetry in the script - A pitfall card in rai-rules-authoring on sparse-derived-property -> ungrounded-solver-constraint symptom
Re-ran paste-test against the trimmed runbook (2026-05-29) in an isolated dir with a fresh subagent that built walkthrough.py from the prompts alone. Verified the three fixes from the prior commit: - Step 2: yield count (5 with Photonic as bridge) -- PASS, naturally reproduced via the named skill. - Step 4: coalesce-to-default guidance in the Response -- PASS, the rules derivation grounded correctly downstream. - Step 6: hedged per-customer service levels -- PASS, margin reproduced EXACTLY ($47,089,150,341 to the cent). - Step 7: persistent-helium semantics in the prompt -- PASS, both iter margins reproduced bit-exactly ($41,960,554,872 and $30,188,075,056, resolving the $1.75B discrepancy from the prior test). - Step 8: PARTIAL on first re-test. Setup note covered the relationship signature (role short_names) but not the entity-binding population pattern. The subagent's natural FK-Property-navigation population (Customer.depends_on(Dependency.downstream, Dependency.upstream)) triggered TyperError on model.path(...).all_paths(). Setup note now includes the working Customer.ref()-based population recipe explicitly. Naturalness sweep also passed -- prompts read as analyst questions (Steps 2/4/6/7 unchanged; Step 8's prompt body is question-shaped with the implementation hint isolated in the Setup note above the prompt block, consistent with the dev-templates-review setup-vs-analyst distinction).
- Template structure tree + What's included now list runbook.md (was missing after the runbook.md addition in 8e03a4b). - Stage 2 forecast-range claim corrected from [0.85, 1.00] (the data-generator clip bounds) to [0.93, 0.99] (actual range across the 216 bundled rows); per-supplier mean 0.95-0.97 added for sanity-check granularity. Matches the range already corrected in runbook.md after paste-test verification. - "How it works" section subheadings de-duped: was '### 1. Stage 1: ...' through '### 4. Stage 4: ...' (numbers and Stage labels both numbered the subsections). Now '### Stage 1: ...' through '### Stage 4: ...'. - Stage 2 snippet: added the pd.read_csv line so the bind makes sense standalone. - Stage 3 compute_effective_capacity snippet: replaced the abbreviated excerpt (ending in '# ... product-level multiplier, then multiply by per-product sum') with the verbatim function body. Satisfies the templates-review "How it works code snippets copied verbatim from script (no cleanup)" rule and prevents drift between README and script. - Stage 3 problem.satisfy snippet: added the name= kwarg dropped in the earlier excerpt; matches the actual constraint declaration. No content changes to the headline narrative, expected output, customization list, or troubleshooting.
… iteration)
Stage 2 (Predictive) now trains a real node-regression GNN on Supplier
predicting capability_pct per (supplier, month). The previous pre-computed
CSV path is preserved behind USE_PRECOMPUTED_FORECAST=True for fast
iteration / offline reproducibility.
New sample data (deterministic from seed=42):
- supplier_features.csv (6 rows × 5 features): equipment_age_months,
geopolitical_exposure_score, region, process_node_nm, workforce_size_k.
- supplier_observations_historical.csv (144 rows = 6 suppliers × 24 months
of past observations, periods -23..0). GNN training labels.
GNN architecture (Stage 2):
- SupplierObservation source concept (identify_by={supplier_id, period_id}).
- Heterogeneous graph: SupplierObservation -> Supplier (216 edges) plus
same-region Supplier -> Supplier edges so feature signal flows between
similar fabs.
- PropertyTransformer: 5 features per Supplier as category/continuous/
integer; PKs/FKs and the target column dropped to prevent leakage.
- Temporal split: train on periods -23..-4 (120 rows), val on -3..0
(24 rows), test = future periods 1..36 (216 rows).
- task_type="regression", eval_metric="rmse", n_epochs=30, lr=0.005.
- Predictions extracted via Source.predictions.predicted_value pattern,
clipped to [0.85, 1.00], bound into the existing SupplierCapabilityForecast
concept so Stage 3/4 see the same ontology surface either path.
Stage 2 setup adds Snowflake prerequisites (EXP_DATABASE + EXP_SCHEMA + 4
RAI Native App grants + GPU-sized predictive reasoner) -- documented in
README Prerequisites with the SQL block. Defaults: MEMORY_SUPPLY /
EXPERIMENTS. EXP_DATABASE/EXP_SCHEMA/GNN_DEVICE/GNN_N_EPOCHS/GNN_LR/GNN_SEED
are labeled top-of-file constants.
Run output (GNN-default, end-to-end verified against the bundled
ontology and Snowflake predictive reasoner test_gpu, 79.9s training):
- iter 0 baseline: OPTIMAL margin=$45,488,032,436
- iter 1 Orion: OPTIMAL margin=$40,523,678,803
- iter 2 helium: OPTIMAL margin=$28,972,506,958
- Margin erosion: $16,515,525,478
- Stage 4 headline reproduces: Apex SPOF, Orion 72 cells / 60.0% drop,
Helium 180 cells widest input impact, 9 dependency paths / 2 multi-hop.
CSV-fallback path (USE_PRECOMPUTED_FORECAST=True) yields ~$47.09B /
$41.96B / $30.19B (the GNN learns slightly lower capability_pct values
from features than the synthetic forecast). README expected output now
shows the GNN-default numbers as headline; both paths' numbers are
documented in runbook Reproducibility notes.
README + runbook updates: Stage 2 "How it works" rewrites for GNN;
template structure tree + What's Included list the two new CSVs;
Prerequisites adds the Snowflake setup block; chain ASCII forecast
range + Step 5 prompt/response rewritten; Reproducibility notes
clarify margins are path-dependent and within-path invariant.
py_compile + ruff clean.
Previously the CSV-fallback path used a feature-driven synthetic forecast (0.93-0.99 range) while the GNN-default path learned slightly lower values (0.92-0.93). Two different code paths produced two different downstream margin numbers, which required a "divergence" caveat in README + runbook. This commit aligns the paths by treating data/supplier_capability_forecast.csv as a snapshot of the GNN's output rather than a parallel synthetic file. The snapshot is refreshed by dev_temp/snapshot_gnn_forecast.py (a developer tool, not template runtime). The customer-facing template itself stays read-only with respect to bundled data -- no write-back to data/ from memory_supply_allocation.py. Verified bit-identical downstream behavior: - USE_PRECOMPUTED_FORECAST=False (GNN-default): $45,488,032,436 / $40,523,678,803 / $28,972,506,958 with margin erosion $16,515,525,478 - USE_PRECOMPUTED_FORECAST=True (CSV path): same numbers, same headline - Stage 9 cascade rankings (Orion 72 cells / 60.0%; Helium 180 cells) identical on both paths README + runbook: drop the GNN-vs-CSV divergence language; reproducibility notes simplified to "invariant across paths." Data generator note clarified that the forecast CSV is GNN-snapshot-managed.
…anup - pyproject.toml: relationalai==1.0.14 -> relationalai[gnn]==1.5.0. The [gnn] extra pulls in the predictive-reasoner dependencies needed for Stage 2's GNN training; 1.5.0 is current and ships the paths library and the predictive-reasoner submodule. - README Prerequisites: matching version text update. - memory_supply_allocation.py: lift the deferred Stage-2 imports (Any / Graph / GNN / PropertyTransformer) to the top of the file alongside the other relationalai.semantics imports. Avoids the inside-conditional import pattern, which the dev-templates-review checklist's import-ordering rule prefers. - README Stage 2 "How it works" GNN snippet: add the stream_logs=False and seed=GNN_SEED kwargs that were missing from the README excerpt, bringing it back to verbatim parity with the script. Drift safety. - v1/README.md index regenerated to include memory_supply_allocation in the v1 catalog (CI gate fix).
|
❤️ |
|
The docs preview for this pull request has been deployed to Vercel!
|
jablonskidev
left a comment
There was a problem hiding this comment.
@cafzal Please implement these changes to bring the README for this template in line with the template for READMEs for templates: https://github.com/RelationalAI/templates/blob/main/sample-template/README.md
| - Supplier-Risk | ||
| --- | ||
|
|
||
| # Memory Supply Allocation |
There was a problem hiding this comment.
You do not need to add an H1 title at the top of the template READMEs. See the template for template READMEs: https://github.com/RelationalAI/templates/blob/main/sample-template/README.md
|
|
||
| # Memory Supply Allocation | ||
|
|
||
| ## What this template is for |
There was a problem hiding this comment.
The section on what this template is for should be one or two short paragraphs that focus on the why and the value of RelationalAI. Limit this section to a quick overview so users can get to the meat of the template faster. Use language that’s accessible to a broad audience.
| @@ -0,0 +1,430 @@ | |||
| --- | |||
| title: "Memory Supply Allocation" | |||
| description: "Monthly rolling-horizon allocation of constrained memory-chip supply across customers with strategic supplier dependencies, named foundries, and raw-material inputs. Four-reasoner chain: predicted supplier capability feeds the LP, customer-customer paths surface single points of failure, and two what-if scenarios trace supplier-offline and input-shortage cascades." | |||
There was a problem hiding this comment.
When you use "LP" the first time and in the tags, spell out that you mean linear programming.
| - **Operations researchers** exploring multi-reasoner pipelines (predictive feeding prescriptive feeding graph) in RelationalAI | ||
| - **Supply-chain analysts** modeling raw-material exposure (helium, neon, etc.) alongside capacity-by-supplier | ||
|
|
||
| ## What you'll build |
There was a problem hiding this comment.
In "What you'll build," list the outcomes rather than the steps. Mention the main RelationalAI features used to achieve these outcomes, but keep it high level.
| ### Tools | ||
| - Python >= 3.10 | ||
| - RelationalAI Python SDK (`relationalai[gnn]==1.5.0`) | ||
|
|
There was a problem hiding this comment.
The template for READMEs for templates calls for a quickstart after Tools: https://github.com/RelationalAI/templates/blob/main/sample-template/README.md
| ├── dependencies.csv | ||
| └── disruption_reveal.csv | ||
| ``` | ||
|
|
There was a problem hiding this comment.
After template structure, include a section for sample data. Describe what the sample data represents and any important notes about its structure or contents.
| ├── dependencies.csv | ||
| └── disruption_reveal.csv | ||
| ``` | ||
|
|
There was a problem hiding this comment.
After Sample data, include a section for Model overview.
Follow this structure:
Model overview
Describe the main entities and the most important relationships.
- Key entities: (e.g.,
product,warehouse,lane) - Primary identifiers: what uniquely identifies each entity
- Important invariants: (e.g., demand non-negative; capacity limits)
Document the data model concept-by-concept.
Concepts (one table per concept)
For each key concept/type:
- Write a brief sentence outside the table describing what the concept represents and how it’s used.
- Add a table with one row per property.
Suggested table shape:
| Property | Type | Identifying? | Notes |
|---|---|---|---|
product_id |
int | Yes | Loaded from data/products.csv |
name |
string | No | Human-readable name |
category |
string | No | Used for grouping/filters |
Repeat this table for each concept (e.g., product, warehouse, lane).
Relationships (only if there are non-property relations)
Only include a Relationships table if the model defines relations beyond concept properties (e.g., standalone predicates like demand(product, date, units) or recursive relations).
| Relationship | Schema (reading string fields) | Notes |
|---|---|---|
demand(product, date, units) |
product, date, units |
Units are weekly; non-negative |
lane(source, destination, capacity) |
source, destination, capacity |
Capacity is per day |
| └── disruption_reveal.csv | ||
| ``` | ||
|
|
||
| ## How it works |
There was a problem hiding this comment.
The walkthrough of the template in "How it works" should be short.
| - **Change the rolling-horizon disruption schedule**: edit `data/disruption_reveal.csv`. Each row is `(reveal_period, target_type, target_id, parameter_name, parameter_value, start_period, end_period, narrative)`. `target_type` is `supplier` or `input`. Increase severity by lowering `parameter_value`; widen the window by adjusting `start_period`/`end_period`. The script automatically picks them up. | ||
| - **Swap pre-computed forecast for a GNN**: replace the load of `supplier_capability_forecast.csv` with a call to `rai-predictive-modeling` and a prediction-extraction step. The `SupplierCapabilityForecast` concept binding stays the same. | ||
| - **Add more suppliers or inputs**: append rows to `suppliers.csv` + `supplier_product_capacity.csv`, or `inputs.csv` + `input_usage.csv`. Re-run; the LP picks up the new entities automatically. | ||
| - **Adjust base floors and yields**: edit `customers.csv` `base_service_floor_pct` and `dependencies.csv` `declared_yield_pct` / `elevated_floor_pct`. The Stage-1 rules pick up new values without code changes. | ||
| - **Extend the dependency graph for longer chains**: add rows to `dependencies.csv`. If you build chains of length > 3, increase `repeat(1, 3)` in Stage 4 accordingly. Avoid cycles — `.all_paths()` returns walks (cycles allowed), which can blow up enumeration. | ||
| - **Change the horizon**: edit `data/periods.csv` (rows) and `HORIZON_END_PERIOD` (constant). Update `disruption_reveal.csv` reveal periods accordingly. | ||
| - **Use net revenue instead of margin**: replace `Product.margin_pct` in the objective with `Product.unit_price_usd_per_gb * Product.margin_pct` (or a new derived `Product.net_revenue_pct`). |
There was a problem hiding this comment.
Group these list items under H3 headings so they follow a visual pattern similar to this:
Customize this template
Focus on the first changes most users will make.
Use your own data
- Where to put files / how to change inputs
- Expected schema and example headers
- Validation checks / common mistakes
Tune parameters
- Where key parameters live
- Suggested defaults and what they change
Extend the model
- Where to add new relations/logic
- How to add a new constraint/metric/output
Scale up / productionize
- Engine sizing guidance (if applicable)
- How to schedule runs / integrate into pipelines
- Notes on reproducibility (pin dependencies, deterministic outputs)
| <summary>rai init fails or connection errors</summary> | ||
|
|
||
| Ensure your Snowflake account has the RAI Native App installed and your user has the required permissions. Run `rai init` to configure your connection profile. See the [RelationalAI documentation](https://docs.relational.ai) for setup details. | ||
| </details> |
There was a problem hiding this comment.
Add a :Learn more" section and a "Support" section following this pattern:
Learn more
This section is the “map” into the RelationalAI docs. Keep it curated.
Group links by purpose, and add a one-line description for each.
Core concepts
- (Link) — What it teaches and how it relates to this template
- (Link)
Language / modeling reference
- (Link)
- (Link)
CLI / SDK guides
- (Link)
- (Link)
Deeper dives (optional)
- (Link) — “If you want to extend X, read this next”
Support
- Where to ask questions / file issues
Address PR #77 review: drop H1, tighten 'What this template is for' to value-focused intro, spell out linear programming, list outcomes in 'What you'll build', fold GNN setup into Prerequisites so Quickstart follows Tools, trim Quickstart output to a confirmation snippet, add Start-here pointer, Sample data, Model overview (per-concept tables), H3-grouped Customize, and Learn more / Support sections.
Summary
v1/memory_supply_allocation/— first paths-using template in the portfolio. Four-reasoner chain on one ontology: Predictive (GNN regression on Supplier) → Rules (customer-customer dependency yield + elevated floor) → Prescriptive (monthly rolling-horizon LP across 36 months with two disruption reveals) → Graph (paths library for dependency-chain enumeration + RCA + two what-if branches).Supplierpredictingcapability_pctper (supplier, month) from 5 static features + 24 months of historical observations.USE_PRECOMPUTED_FORECAST=Trueflag short-circuits to a pre-computed CSV (a snapshot of the GNN's output) for fast iteration / offline reproducibility — both paths produce bit-identical downstream margins.Σ_suppliers (nominal × capability_pct) × Π_inputs (1 − intensity × (1 − availability)).compute_effective_capacityhelper as the LP, so structural impact stays consistent with the optimization. Supplier-offline ranks Orion Foundry as widest impact (72 cells, 60.0% max cap drop); input-shortage ranks Helium as widest (180 cells across all 5 SKUs).Customer.is_dependency_spof,Customer.elevated_floor_pct,SupplierCapabilityForecast.capability_pct,EffectiveCapacity(iter-tagged),ScenarioOutcome.total_margin_usd,Supplier.offline_impact_cells,Input.shortage_impact_cells. All queryable after the script exits.runbook.md— analyst-facing paste-testable walkthrough, one prompt per stage, paste-tested against fresh/rai-*skill sessions.Run output
Test plan
python -m ruff check memory_supply_allocation.pycleanpython -m py_compile memory_supply_allocation.pypassespython memory_supply_allocation.pyexits 0GPU_NV_Spredictive reasoner; predictions land in [0.85, 1.00]OPTIMALCustomer.is_dependency_spofontology query returnsApex Photonic ComponentsUSE_PRECOMPUTED_FORECAST=Trueshort-circuit to CSV path produces bit-identical numbers to the GNN pathdev-templates-reviewchecklist passescd v1/memory_supply_allocation && python -m pip install .succeeds in a clean venv — pending reviewer verification