Schema Change Management: Zero-Downtime Ontology Evolution
Nightmare scenario:
CoomiaPublished on August 13, 202518 min read
Share this articleTwitter / X
Schema Change Management: Zero-Downtime Ontology Evolution
“Series: S4 Ontology Modeling · Article 9 | Level: Intermediate | Reading Time: 18 min
#TL;DR
- Ontology Schemas are not static — business evolution means ObjectTypes need new properties, type changes, and field deletions. coomia-dip provides Schema versioning and safe migration mechanisms to ensure changes never break existing data or consumers.
- Three-phase migration protocol (Propose, Validate, Apply) ensures every Schema change goes through compatibility checking, impact analysis, and data migration verification, eliminating the "changed Schema and everything exploded" scenario.
- Backward compatibility rules are auto-evaluated — adding optional properties (safe), modifying types (requires validation), deleting properties (dangerous) are automatically classified with migration recommendations.
#1. Why Schema Change Management Is Critical
#1.1 Schema Changes Without Version Control
Code
Nightmare scenario:
Monday: DBA changes Order.status from STRING to ENUM
Tuesday: Reporting team's ETL pipelines all fail — they use status LIKE '%active%'
Wednesday: Frontend team finds dropdowns broken — API ENUM values don't match
Thursday: Data science team's model training fails — feature column type changed
Friday: Rollback! But rollback also breaks — new ENUM values can't convert back to STRING
Root cause analysis:
├── No change impact analysis
├── No downstream consumer notification
├── No data migration plan
├── No rollback strategy
└── No compatibility checking
#1.2 coomia-dip Schema Versioning
Code
coomia-dip Schema change workflow:
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Propose │ → │Validate │ → │ Preview │ → │ Apply │
│ Submit │ │Compat │ │ Impact │ │ Execute │
│ change │ │ check │ │ preview │ │migration│
└─────────┘ └─────────┘ └─────────┘ └─────────┘
│ │
↓ ↓
Incompatible? Auto data migration
Reject or require + version increment
explicit confirmation
Each ObjectType has version history:
Order v1: {orderId, status: STRING, amount: DOUBLE}
Order v2: {orderId, status: ENUM, amount: DOUBLE, createdAt: TIMESTAMP}
Order v3: {orderId, status: ENUM, totalAmount: DOUBLE, createdAt: TIMESTAMP}
↑ amount renamed to totalAmount
#2. Schema Change Classification
#2.1 Change Type Matrix
Code
Change types and risk ratings:
┌─────────────────────────┬────────┬──────────────────────────────┐
│ Change Type │ Risk │ Description │
├─────────────────────────┼────────┼──────────────────────────────┤
│ Add optional property │ SAFE │ Old data unaffected, optional │
│ Add required + default │ SAFE │ Old data auto-filled │
│ Add index │ SAFE │ Async background build │
│ Rename property │ MEDIUM │ API consumers need update │
│ Widen type range │ MEDIUM │ INT→LONG, STRING→TEXT safe │
│ Add enum value │ MEDIUM │ Old consumers may not know it │
│ Change property type │ HIGH │ May cause data loss │
│ Narrow type range │ HIGH │ LONG→INT may overflow │
│ Delete property │ HIGH │ Dependent consumers will fail │
│ Delete enum value │ HIGH │ Existing data may contain it │
│ Add required no default │ HIGH │ Old data can't satisfy constr │
│ Change primary key │ BLOCK │ Breaks all relations/refs │
└─────────────────────────┴────────┴──────────────────────────────┘
#2.2 Compatibility Rules Engine
Code
Compatibility checking engine:
Input: Current Schema + Change Request
Output: Compatibility verdict + Migration recommendations
Rule 1: Add property
IF property nullable == true OR default != null:
→ COMPATIBLE (safe)
ELSE:
→ BREAKING (dangerous: old data lacks this field)
→ Suggestion: Add default value or make optional
Rule 2: Type change
Compatible type pairs (safe widening):
BOOLEAN → STRING ✓
INT → LONG → DOUBLE ✓
STRING → TEXT ✓
DATE → TIMESTAMP ✓
Incompatible type pairs (data loss risk):
DOUBLE → INT ✗ (precision loss)
STRING → INT ✗ (format mismatch)
TIMESTAMP → DATE ✗ (time info lost)
Rule 3: Delete property
Scan all dependencies:
Derived property dependency? → BREAKING
ActionType parameter dependency? → BREAKING
RelationType reference? → BREAKING
External API consumer? → WARNING
IF no dependencies:
→ COMPATIBLE (but recommend marking @Deprecated first)
Rule 4: Enum changes
Add value: COMPATIBLE (old consumers may need update)
Remove value:
IF existing data contains that value: BREAKING
IF existing data does not contain it: COMPATIBLE (but verify)
Rename value: BREAKING (essentially delete old + add new)
#3. Three-Phase Migration Protocol
#3.1 Phase 1: Propose
Code
API: POST /api/v1/ontology/schema/proposals
Request:
{
"objectTypeId": "Order",
"changes": [
{
"type": "ADD_PROPERTY",
"property": {
"name": "priority",
"dataType": "ENUM",
"enumValues": ["LOW", "MEDIUM", "HIGH", "URGENT"],
"nullable": false,
"defaultValue": "MEDIUM"
}
},
{
"type": "MODIFY_PROPERTY",
"propertyName": "amount",
"modifications": {
"rename": "totalAmount",
"dataType": "DECIMAL"
}
},
{
"type": "DEPRECATE_PROPERTY",
"propertyName": "legacyCode",
"deprecationMessage": "Use 'orderCode' instead",
"removalVersion": "v5"
}
],
"description": "Add priority field, rename amount to totalAmount with DECIMAL",
"author": "alice@company.com"
}
Response:
{
"proposalId": "prop-20250115-001",
"status": "PENDING_VALIDATION",
"version": {
"current": "v3",
"proposed": "v4"
},
"changes": [...],
"createdAt": "2025-01-15T10:00:00Z"
}
#3.2 Phase 2: Validate
Code
API: POST /api/v1/ontology/schema/proposals/{proposalId}/validate
Automatically executed checks:
┌──────────────────────────────────────────────────────┐
│ Schema Change Validation Report │
│ Proposal: prop-20250115-001 │
│ ObjectType: Order (v3 → v4) │
├──────────────────────────────────────────────────────┤
│ │
│ Change 1: ADD_PROPERTY "priority" │
│ ├── Compatibility: COMPATIBLE │
│ ├── Reason: Has default value "MEDIUM" │
│ ├── Data migration: None required │
│ └── Impact: None │
│ │
│ Change 2: RENAME "amount" → "totalAmount" │
│ ├── Compatibility: REQUIRES_MIGRATION │
│ ├── Reason: Property name change │
│ ├── Data migration: Column rename (zero-copy) │
│ └── Impact: │
│ ├── 3 Derived Properties reference "amount" │
│ │ → Will auto-update to "totalAmount" │
│ ├── 2 ActionTypes use "amount" as parameter │
│ │ → Require manual update │
│ ├── 1 RelationType filters on "amount" │
│ │ → Will auto-update │
│ └── External APIs: /api/v1/orders response │
│ → Add alias "amount" → "totalAmount" │
│ │
│ Change 3: TYPE_CHANGE "amount" DOUBLE → DECIMAL │
│ ├── Compatibility: REQUIRES_MIGRATION │
│ ├── Reason: Type widening (safe direction) │
│ ├── Data migration: CAST(amount AS DECIMAL(18,4)) │
│ ├── Estimated time: ~30s for 1M rows │
│ └── Impact: None (DECIMAL is superset of DOUBLE) │
│ │
│ Change 4: DEPRECATE "legacyCode" │
│ ├── Compatibility: COMPATIBLE │
│ ├── Reason: Deprecation only, not removal │
│ └── Impact: Consumers will see @Deprecated warning │
│ │
│ Overall: COMPATIBLE_WITH_MIGRATION │
│ Estimated migration time: ~35 seconds │
│ Requires confirmation: YES (rename + type change) │
└──────────────────────────────────────────────────────┘
#3.3 Phase 3: Apply
Code
API: POST /api/v1/ontology/schema/proposals/{proposalId}/apply
Execution process (step-by-step, each step rollbackable):
Step 1: Create new Schema version (v4)
├── Register v4 in Schema Registry
├── v3 and v4 both active (dual-version coexistence period)
└── Duration: < 1 second
Step 2: Data migration
├── Add column "priority" DEFAULT 'MEDIUM'
├── Rename column "amount" → "totalAmount"
├── Type conversion DOUBLE → DECIMAL
├── Online DDL (no table locks)
└── Duration: ~35 seconds
Step 3: Update derived properties
├── Scan all derived property expressions referencing "amount"
├── Auto-replace with "totalAmount"
├── Re-validate expression legality
└── Duration: < 5 seconds
Step 4: Update API layer
├── Add property alias: amount → totalAmount
├── API accepts both old and new names (compatibility period)
├── Set compatibility period deadline (default 30 days)
└── Duration: < 1 second
Step 5: Publish change notifications
├── Notify all registered Schema change listeners
├── Send change log to audit system
├── Update SDK type definitions
└── Duration: < 1 second
Total time: ~42 seconds (35 seconds for data migration)
Zero downtime throughout, reads and writes unaffected
#4. Data Migration Strategies
#4.1 Online vs Offline Migration
Code
Online Migration — default strategy:
Applicable when:
├── Data volume < 10 million rows
├── Change type is safe widening
└── Minor performance impact acceptable (<10%)
Implementation:
1. Double Write
New data written in both old and new formats
2. Background Backfill
Background thread migrates historical data in batches
3. Cutover
After backfill completes, switch to new format
4. Cleanup
Delete old format data
Timeline:
T0: Start double write
T0~T1: Background backfill (minutes to hours)
T1: Backfill complete, verify data consistency
T2: Switch to new format
T3: Cleanup old format data
Offline Migration — for large datasets:
Applicable when:
├── Data volume > 10 million rows
├── Change type is breaking
└── Precise verification needed
Implementation:
1. Snapshot current data
2. Transform on snapshot
3. Verify transformed data
4. Atomic switch to new data
#4.2 Type Conversion Rules
Code
Safe type conversions (auto-executed):
Source → Target Conversion rule
BOOLEAN → STRING "true" / "false"
INT → LONG Direct widening
INT → DOUBLE Direct widening
LONG → DOUBLE Direct widening (precision note)
FLOAT → DOUBLE Direct widening
STRING → TEXT Direct widening
DATE → TIMESTAMP Append "T00:00:00Z"
ENUM → STRING Use enum value string representation
Type conversions requiring validation (row-by-row check):
Source → Target Validation rule
STRING → INT Every row must be valid integer
STRING → DOUBLE Every row must be valid number
STRING → DATE Every row must match date format
STRING → ENUM Every row must be in enum values list
DOUBLE → INT Fractional part must be 0
TIMESTAMP → DATE Time portion discarded (requires confirm)
Validation report example:
┌────────────────────────────────────────────────┐
│ Type Conversion Validation │
│ STRING → INT for "Order.legacyAmount" │
├────────────────────────────────────────────────┤
│ Total rows: 1,000,000 │
│ Valid rows: 999,847 │
│ Invalid rows: 153 │
│ │
│ Sample invalid values: │
│ Row 12345: "N/A" │
│ Row 67890: "123.45" │
│ Row 99001: "" │
│ Row 99502: "unknown" │
│ │
│ Action required: │
│ ├── Fix invalid data before migration │
│ ├── Or provide a fallback value │
│ └── Or change target type to allow nulls │
└────────────────────────────────────────────────┘
#4.3 Auto-Generated Migration Scripts
Code
coomia-dip auto-generates migration scripts:
Example: Order v3 → v4 migration script
-- Migration: Order v3 → v4
-- Generated: 2025-01-15T10:05:00Z
-- Author: system (auto-generated)
-- Step 1: Add new column "priority"
ALTER TABLE order_objects
ADD COLUMN priority VARCHAR(20) DEFAULT 'MEDIUM' NOT NULL;
-- Step 2: Rename column "amount" to "totalAmount"
ALTER TABLE order_objects
RENAME COLUMN amount TO total_amount;
-- Step 3: Change type DOUBLE → DECIMAL
ALTER TABLE order_objects
ALTER COLUMN total_amount TYPE DECIMAL(18,4)
USING CAST(total_amount AS DECIMAL(18,4));
-- Step 4: Update indexes
CREATE INDEX CONCURRENTLY idx_order_priority
ON order_objects(priority);
-- Step 5: Add deprecation marker for "legacyCode"
COMMENT ON COLUMN order_objects.legacy_code IS
'@Deprecated: Use orderCode instead. Removal in v5.';
-- Rollback script (auto-generated):
-- ALTER TABLE order_objects DROP COLUMN priority;
-- ALTER TABLE order_objects RENAME COLUMN total_amount TO amount;
-- ALTER TABLE order_objects ALTER COLUMN amount TYPE DOUBLE PRECISION;
-- DROP INDEX idx_order_priority;
Every migration script has a corresponding rollback script.
Rollback scripts are verified for executability before Apply.
#5. Version Compatibility Management
#5.1 API Compatibility Layer
Code
After Schema changes, API must support multi-version consumers:
Scenario: Order.amount renamed to Order.totalAmount
API compatibility strategy:
v3 consumer (old) requests /api/v1/orders/123:
{
"orderId": "123",
"amount": 610.13, ← old name still works
"status": "ACTIVE"
}
v4 consumer (new) requests /api/v1/orders/123:
{
"orderId": "123",
"totalAmount": 610.13, ← new name
"priority": "HIGH", ← new property
"status": "ACTIVE"
}
Unversioned consumers — receive latest version
Versioned consumers:
GET /api/v1/orders/123?schemaVersion=v3
→ Returns v3 format (using property alias mapping)
Compatibility period policy:
v3 alias validity: 30 days after v4 release
After 30 days: Using old name returns Deprecation Warning Header
After 60 days: Using old name returns 400 Bad Request
#5.2 SDK Auto-Update
Code
After Schema changes, SDK auto-generates new type definitions:
Python SDK changes:
# v3 (old version)
class Order(OntologyObject):
order_id: str
amount: float
status: str
# v4 (new version - auto-generated)
class Order(OntologyObject):
order_id: str
total_amount: Decimal # renamed + type change
priority: OrderPriority # new property
status: str
legacy_code: str | None # marked @deprecated
@deprecated("Use 'total_amount' instead")
@property
def amount(self) -> Decimal:
return self.total_amount
SDK versioning:
SDK 1.0.x → Order v3
SDK 1.1.x → Order v4 (backward compatible with v3 aliases)
SDK 2.0.x → Order v4 (v3 aliases removed)
#5.3 Consumer Notification Mechanism
Code
Schema change notification flow:
Change proposed → Validation passes → Send notifications
Notification channels:
├── Webhook — push to registered consumer endpoints
├── Event Bus — publish to Kafka topic "schema-changes"
├── Email — send to affected ObjectType owners
└── Dashboard — display change alerts in admin console
Notification content:
{
"eventType": "SCHEMA_CHANGE_PROPOSED",
"objectType": "Order",
"version": {"from": "v3", "to": "v4"},
"changes": [
{"type": "ADD_PROPERTY", "property": "priority"},
{"type": "RENAME_PROPERTY", "from": "amount", "to": "totalAmount"},
{"type": "TYPE_CHANGE", "property": "totalAmount",
"from": "DOUBLE", "to": "DECIMAL"}
],
"impact": {
"derivedProperties": 3,
"actionTypes": 2,
"externalConsumers": 5
},
"compatibilityPeriod": "30 days",
"proposedApplyDate": "2025-01-20T00:00:00Z"
}
Consumer responses:
├── ACK — Acknowledged, will update within compatibility period
├── NACK — Object to change, need more time
├── REQUEST_EXTENSION — Request extended compatibility period
└── No response (timeout) — System sends reminder
#6. Version Rollback
#6.1 Auto-Rollback Triggers
Code
The following conditions automatically trigger rollback:
1. Data migration step fails
→ All executed steps are rolled back
→ Revert to pre-change Schema version
2. Post-migration validation fails
→ Data integrity check does not pass
→ Roll back data and Schema
3. Manual rollback trigger
→ Administrator discovers issues
→ API: POST /api/v1/ontology/schema/rollback/{version}
Rollback constraints:
├── Can only roll back to previous version (v4 → v3)
├── If new data uses new Schema-specific values, rollback must handle
│ Example: v4 added "priority" property, 1000 records already have values
│ On rollback: those 1000 records' priority values will be lost
│ → System warns and requires explicit confirmation
└── After rollback protection period (default 7 days), old version data may be cleaned
#6.2 Rollback Strategy
Code
Rollback execution steps:
Step 1: Stop new version data writes
├── API layer switches back to old Schema
└── New data written using old Schema
Step 2: Data reverse-migration
├── Execute auto-generated rollback script
├── Verify reverse-migrated data integrity
└── Handle values in new data that old Schema cannot express
Step 3: Restore dependencies
├── Derived property expressions restored
├── ActionType parameters restored
├── API aliases removed
└── SDK rollback notification
Step 4: Verification
├── Data integrity check
├── Derived properties recomputation
├── API end-to-end testing
└── Consumer health check
Step 5: Publish rollback notification
├── Notify all consumers that Schema has been rolled back
└── Record rollback reason in audit log
#7. Schema Change Best Practices
#7.1 Incremental Changes
Code
Recommended change pattern — step by step, not all at once:
Not recommended: Direct rename and type change
v3 → v4: amount(DOUBLE) → totalAmount(DECIMAL)
Risk: One change contains two breaking operations
Recommended: Split into two changes
v3 → v4: Add totalAmount(DECIMAL), keep amount
Background sync amount → totalAmount
v4 → v5: Mark amount as @Deprecated
v5 → v6: After confirming no consumers use amount, delete it
Each change does one thing:
├── Either add
├── Or rename
├── Or change type
├── Or delete
└── Never mix multiple breaking operations
#7.2 Schema Change Log
Code
Every Schema change is recorded in the audit log:
SchemaChangeLog:
├── changeId: "sch-20250115-001"
├── objectTypeId: "Order"
├── versionFrom: "v3"
├── versionTo: "v4"
├── changes: [...]
├── author: "alice@company.com"
├── approver: "bob@company.com"
├── proposedAt: "2025-01-15T10:00:00Z"
├── validatedAt: "2025-01-15T10:05:00Z"
├── appliedAt: "2025-01-15T10:10:00Z"
├── migrationDurationMs: 35000
├── affectedRecords: 1000000
├── status: "COMPLETED"
└── rollbackAvailableUntil: "2025-01-22T10:10:00Z"
Query history:
GET /api/v1/ontology/schema/changelog?objectTypeId=Order
Purposes:
├── Audit: Who changed what and when
├── Debug: What did the Schema look like at a given time
├── Compliance: Who approved the change
└── Tracing: Trace data issues back to Schema changes
#7.3 Schema Design Principles
Code
Principles for designing Schema with future changes in mind:
Principle 1: Design loosely
├── String fields use TEXT not VARCHAR(50)
├── Numeric fields use DECIMAL not INT
├── Date fields use TIMESTAMP not DATE
└── Reserve extension fields (metadata: JSON)
Principle 2: Semantic naming
├── Use business semantics: totalAmount not amt
├── Use consistent naming: createdAt, updatedAt, deletedAt
└── Avoid abbreviations: description not desc
Principle 3: Version awareness
├── APIs always include version numbers
├── Consumers declare supported version ranges
├── Schema changes have adequate compatibility periods
└── Automated tests cover multi-version compatibility
Principle 4: Reversibility
├── Every change has a rollback plan
├── Deprecate before deleting
├── Type changes prefer safe widening direction
└── Preserve pre-change data snapshots
#8. Automated Schema Evolution
#8.1 Schema Change Detection
Code
coomia-dip can infer Schema change needs from data patterns:
Scenario: Data mismatch detected during write
Message queue receives:
{
"orderId": "ORD-2025-001",
"totalAmount": 610.13,
"priority": "HIGH", ← Not in Schema!
"customerSegment": "VIP" ← Not in Schema!
}
Auto-inference flow:
1. Detect unknown properties "priority" and "customerSegment"
2. Analyze last 100 records, confirm this isn't sporadic dirty data
priority appears 98/100 times, values = {LOW, MEDIUM, HIGH, URGENT}
customerSegment appears 95/100 times, values = {VIP, REGULAR, NEW}
3. Auto-generate Schema change proposal:
ADD_PROPERTY priority: ENUM(LOW, MEDIUM, HIGH, URGENT)
ADD_PROPERTY customerSegment: ENUM(VIP, REGULAR, NEW)
4. Send notification to ObjectType owner for approval
5. Apply automatically after approval
Note: Auto-inference can only suggest adding properties.
Type changes and deletions must be initiated manually.
#8.2 Schema Diff Comparison
Code
API: GET /api/v1/ontology/schema/diff?from=v3&to=v4&objectTypeId=Order
Response:
{
"objectTypeId": "Order",
"from": "v3",
"to": "v4",
"diff": {
"added": [
{"name": "priority", "type": "ENUM",
"values": ["LOW","MEDIUM","HIGH","URGENT"]}
],
"modified": [
{
"name": "amount → totalAmount",
"changes": {
"name": {"from": "amount", "to": "totalAmount"},
"type": {"from": "DOUBLE", "to": "DECIMAL(18,4)"}
}
}
],
"deprecated": [
{"name": "legacyCode", "message": "Use orderCode instead",
"removalVersion": "v5"}
],
"removed": []
},
"compatibility": "BACKWARD_COMPATIBLE_WITH_MIGRATION",
"migrationRequired": true
}
#9. Multi-Environment Schema Synchronization
#9.1 Environment Promotion Flow
Code
Schema changes promoted across environments:
Development (dev) → Staging (staging) → Production (prod)
Flow:
1. dev environment: Free changes, no approval needed
2. staging environment: Sync Schema from dev, run integration tests
3. prod environment: Promote from staging, requires approval
Schema sync API:
POST /api/v1/ontology/schema/promote
{
"objectTypeId": "Order",
"fromEnvironment": "staging",
"toEnvironment": "prod",
"version": "v4"
}
Pre-promotion checks:
├── All integration tests pass in staging
├── Data migration verified in staging
├── Consumer compatibility tests pass
├── Rollback plan is ready
└── Approver has approved
#9.2 Schema Locking
Code
Schema locking mechanism for critical ObjectTypes:
Lock levels:
UNLOCKED — Anyone can change
SOFT_LOCK — Changes require owner approval
HARD_LOCK — Changes require multi-person approval (2/3 approvers)
FROZEN — No changes allowed (unless unfrozen)
Set lock:
PUT /api/v1/ontology/schema/lock
{
"objectTypeId": "Order",
"lockLevel": "HARD_LOCK",
"approvers": ["alice", "bob", "carol"],
"reason": "Production release freeze"
}
Use cases:
├── Release freeze: FROZEN
├── Core model protection: HARD_LOCK
├── Day-to-day governance: SOFT_LOCK
└── Experimental models: UNLOCKED
#10. Schema Changes and Derived Property DAG Interaction
Code
Schema changes affect the DAG:
Scenario: Rename Order.amount → Order.totalAmount
DAG impact analysis:
1. Scan all DAG nodes referencing "Order.amount"
2. Found:
Customer.lifetimeValue expression references Order.amount
Order.profit expression references amount
3. Auto-update:
Customer.lifetimeValue: "SUM(Order.amount)" → "SUM(Order.totalAmount)"
Order.profit: "amount - cost" → "totalAmount - cost"
4. Re-validate DAG:
Expression syntax check ✓
Cycle detection ✓
Type compatibility check ✓
Scenario: Delete Order.legacyField
DAG impact analysis:
1. Scan all DAG nodes referencing "Order.legacyField"
2. Found: Order.legacyScore = legacyField * 0.5
3. Conclusion: Cannot delete! legacyField is a derived property dependency
4. Suggestion: Delete Order.legacyScore first, then delete Order.legacyField
Operation order:
Step 1: Delete derived property Order.legacyScore
Step 2: Remove legacyScore node from DAG
Step 3: Delete source property Order.legacyField
Step 4: Re-validate DAG integrity
#Key Takeaways
- Schema change is the norm for Ontology evolution — coomia-dip transforms Schema changes from "high-risk operations" to "controlled daily procedures" through versioning, compatibility checking, and auto-migration, eliminating the fear of "changing Schema breaks everything."
- The three-phase protocol is the safety valve — Propose (record intent) then Validate (auto-check) then Apply (controlled execution). Each phase can be interrupted and rolled back, ensuring no "system unavailable mid-change" scenarios.
- The compatibility rules engine auto-classifies — safe changes pass automatically, dangerous changes require confirmation, forbidden changes are rejected outright, not relying on human judgment for safety.
- Multi-version API and SDK support — through property aliases and version negotiation, old and new consumers coexist peacefully, giving downstream adequate migration time.
- Schema changes interlock with the DAG — renaming properties auto-updates derived property expressions, deleting properties first checks DAG dependencies, ensuring Schema changes never silently break computation chains.
#Next Article
The next article S4-10 Metrics as Ontology discusses how to unify monitoring metrics and business KPIs into the Ontology model — no longer treating metrics as a separate system but making them part of ObjectTypes, enabling unified querying and correlated analysis of "business data" and "operational metrics."
#ontology #schema-evolution #version-control #migration #backward-compatibility #breaking-change #data-migration #api-versioning