Discover the real warehouse before moving it.

Inventory Schemas, ETL Jobs, Reports, Stored Procedures, Dependencies, SLAs, and Hidden Business Logic

Inventory legacy data, executable logic, dependencies, consumers, and service expectations before modernization.

Intermediate → Advanced145–190 minutesinventory + lineage labmigration + semantic preservationLast reviewed: September 2026

Learning outcomes

01

Inventory schemas, ETL jobs, reports, stored procedures, dependencies, SLAs, roles, and consumers before choosing a migration strategy.

02

Separate physical source rows from governed business semantics and detect hidden filters, time rules, and exclusions.

03

Build a dependency graph that reaches consumer reports rather than stopping at the warehouse table.

04

Prove why row counts alone cannot validate a modernization.

05

Produce an evidence-backed migration inventory that can drive cutover, rollback, and retirement decisions.

Continuity: migration may move implementation, not meaning

Chapter 29 begins from the governed AtlasMart state through Chapter 28: 10 current paid lines, 8 orders, 12 units, 820 USD gross revenue, 495 USD cost, and 325 USD gross profit, with source waterline 208. The sales fact grain remains one paid order line; gross_revenue_usd.v1 remains paid line amount in USD under its governed filters and UTC time semantics. A platform migration is not permission to redefine those contracts.

Executed local harness and assumptions

The mandatory lab is free/local/synthetic and was executed with Python 3.13.5 and SQLite 3.46.1. SQLite supplies tables, views, transactions, UPSERT and query-plan evidence, but it does not implement stored procedures, cloud roles, CDC connectors, or managed-warehouse cost controls. Stored-procedure behavior and access roles are therefore represented as explicit metadata/policy fixtures, while SQL correctness and restart/idempotency behavior are executed locally. Time zone is UTC; no production credentials or personal data are used.

1. Problem frame: the table says 860 USD, finance says 820 USD

AtlasMart's legacy EDW has accumulated years of SQL, scheduled jobs, report filters, procedure code, service identities, and operational promises. A modernization team discovers a compact sales_line table and proposes to copy it into a new platform first, then “fix reports later.” The raw table has eleven paid-looking rows and 860 USD of line amount. Finance's certified report has only ten paid lines and 820 USD. Neither side is necessarily wrong: the report applies a hidden rule that excludes internal test orders.

The first migration question is therefore not “How do we copy this table?” It is “Where is business meaning encoded, who depends on it, and what evidence will prove that the new system behaves the same?”

2. Inventory state surfaces, not just tables

A migration inventory is a structured list of data objects, executable transformations, interfaces, consumers, owners, security boundaries, schedules, and service expectations that must either move, be replaced, or be retired. Schema DDL is only one slice. ETL jobs encode sequencing and retry behavior. Stored procedures and views can hide business filters. Reports can add last-mile logic. SLAs/SLOs encode consumer expectations. Credentials and roles determine who can bypass governed views.

Asset class AtlasMart example What must be captured Failure if omitted
Schema/table legacy.sales_line grain, keys, columns, row semantics, retention rows move but meaning is unknown
ETL job job_refresh_finance_daily schedule, inputs, waterline, retries, owner new data arrives late or duplicates
Procedure/view sp_refresh_finance_sales / legacy_finance_report filters, timezone, joins, exclusions 820 USD becomes 860 USD
Report rpt_exec_revenue metric version, filters, consumers dashboard silently changes
SLA ready by 08:30 UTC clock, completeness, exception policy cutover is “successful” but too late
Security finance_report_reader allowed surfaces and bypass paths least privilege regresses
Consumer finance_controller contact, criticality, migration readiness breakage has no accountable recipient

3. Hidden business logic is executable metadata

The lab's legacy physical table contains one synthetic TEST900 row. The governed view applies status='paid' AND is_test_order=0. The second predicate is easy to miss because the column exists physically but its business significance lives in procedure/report code, not in the table name.

sql
CREATE VIEW legacy_finance_report ASSELECT *FROM sales_lineWHERE status = 'paid'  AND is_test_order = 0;-- Raw physical stateSELECT COUNT(*), SUM(line_amount_usd) FROM sales_line;-- 11 rows, 860 USD-- Governed business stateSELECT COUNT(*), SUM(line_amount_usd) FROM legacy_finance_report;-- 10 rows, 820 USD

4. Dependency discovery must reach people and products

A dependency graph is directed: a source feeds a job; the job writes a table; a procedure derives a daily surface; reports query it; named consumers depend on those reports. Stopping lineage at legacy.finance_daily underestimates blast radius. Migration readiness needs the transitive path to every report, metric, export, service, and human owner that can observe a semantic change.

text
erp.orders  -> job_extract_erp_orders  -> legacy.sales_line  -> sp_refresh_finance_sales  -> legacy.finance_daily      -> rpt_finance_daily -> finance_controller      -> rpt_exec_revenue  -> executive_dashboard

5. SLA inventory is part of semantics

Data can be numerically correct and still fail migration acceptance if it arrives after the decision window. AtlasMart records “certified finance report ready by 08:30 UTC” as an owned contract. That contract needs its source-ready assumption, completeness rule, timezone, exception policy, and consumer. A platform that returns 820 USD at noon is not equivalent for an 08:30 operational process.

6. Controlled failure: migrate tables first

Wrong approach

Copy the legacy table, confirm eleven source rows equal eleven target rows, and declare the data phase complete.

Diagnosis: row-count parity proves only that a physical set was copied. It does not prove which rows contribute to governed revenue, how UTC days are derived, whether report filters survived, or whether consumer access changed. The naïve modern report therefore reproduces the physical 860 USD rather than the governed 820 USD.

Repair: inventory executable logic before migration, convert each hidden rule into an explicit versioned contract/test, then reconcile old and new consumer-visible results. Row counts remain useful as one test, but they are subordinate to grain, metric, history, and access semantics.

Expected evidence
legacy physical: (11, 9, 13, 860, 515, 345)legacy governed: (10, 8, 12, 820, 495, 325)naive modern:   (11, 9, 13, 860, 515, 345)corrected new:  (10, 8, 12, 820, 495, 325)history sha256: 240cc2c5a2ae0fdb58be216e6a560f3975f36cb7903ff2e340778e756508bb8a

7. Local lab: build and query the migration inventory

python
import json, sqlite3from pathlib import Pathroot = Path("atlasmart_ch29_lab")root.mkdir(exist_ok=True)conn = sqlite3.connect(root / "legacy.db")conn.executescript("""CREATE TABLE sales_line(  order_id TEXT, line_no INTEGER, line_amount_usd INTEGER,  status TEXT, is_test_order INTEGER,  PRIMARY KEY(order_id,line_no));INSERT INTO sales_line VALUES ('O1007',1,50,'paid',0);INSERT INTO sales_line VALUES ('TEST900',1,40,'paid',1);CREATE VIEW legacy_finance_report ASSELECT * FROM sales_lineWHERE status='paid' AND is_test_order=0;""")print(conn.execute("SELECT SUM(line_amount_usd) FROM sales_line").fetchone()[0])print(conn.execute("SELECT SUM(line_amount_usd) FROM legacy_finance_report").fetchone()[0])inventory = {  "stored_procedures": ["sp_refresh_finance_sales"],  "reports": ["rpt_finance_daily", "rpt_exec_revenue"],  "sla": "certified finance report ready by 08:30 UTC",  "hidden_logic": ["status='paid'", "is_test_order=0", "UTC day"]}(root / "migration_inventory.json").write_text(json.dumps(inventory, indent=2))# Expected: 90 then 50 in this tiny focused fixture.

8. Verification checklist

  • Every migrated table has a declared business grain and owner.
  • Stored procedure/view/report SQL has been scanned for filters, timezone logic, currency/unit rules, deduplication, and special members.
  • Lineage reaches named reports/consumers.
  • SLAs/SLOs and security surfaces are inventory items, not afterthoughts.
  • At least one consumer-visible golden result exists for each critical metric.
Blast radius and reset

All destructive actions target only a disposable atlasmart_ch29_lab directory. Never point these commands at a production warehouse. Reset with python -c "import shutil; shutil.rmtree('atlasmart_ch29_lab', ignore_errors=True)" and rerun the fixture from a clean directory.

9. Production judgment and bridge

The inventory phase is complete only when the migration team can answer what must remain equivalent, who will notice a difference, and how that difference will be measured. Missing documentation is itself a migration risk signal. Chapter 29 next moves from discovery to the strategy choice: rehost, replatform, or refactor—and explains why copying technical debt onto newer infrastructure is not modernization.

Knowledge check

Checkpoint

Why is a matching row count insufficient migration evidence?

Show answer

Because row counts validate physical cardinality only. They do not prove grain semantics, hidden filters, metric formulas, timezone behavior, history, security, or consumer-visible query results.

Checkpoint

Where should hidden business logic be looked for?

Show answer

In ETL code, stored procedures, views, BI/report filters, semantic models, scheduled scripts, manual adjustment files, and sometimes operational runbooks—not only table DDL.

Checkpoint

Why does an SLA belong in the migration inventory?

Show answer

Because timing and completeness are part of the consumer contract. Correct data delivered after the decision window can still be a failed migration.

Checkpoint

What does the 820-vs-860 fixture prove?

Show answer

It proves that the legacy governed surface contains semantics not implied by copying the physical table. It does not prove every real legacy system uses the same kind of exclusion rule.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.