schema-lint chassis v1.0: DropProperty Soft + code-tagged diagnostics (MR-694) - #90
Conversation
25064ca to
48ba696
Compare
First commit of the chassis v1 branch. Lands a small, foundational
slice without behavior change, plus a planning doc that lays out the
remaining 7 commits in sequence so the PR can be reviewed
incrementally.
This commit:
- Adds SchemaMigrationStep::diagnostic() returning the full
&'static DiagnosticCode (family + tier + severity) for
UnsupportedChange steps with codes. Renderers can now reach the
tier without re-implementing the code → tier lookup.
- CLI `omnigraph schema plan` output now displays tier alongside
code:
unsupported change on node:Person.age [OG-DS-104, destructive]:
removing property 'Person.age' is not supported in schema
migration v1
Operators see at-a-glance the kind of risk each rejection
represents — not just the rule identifier.
- No behavior change. All 11 existing schema_apply tests still pass.
Planning doc at docs/schema-lint-v1-plan.md tracks the 7 remaining
commits to bring v1 to feature-complete:
1. (this commit) Tier surfacing in plan output.
2. Soft / Hard mode enum on drop steps.
3. Tombstone fields on catalog IR.
4. Planner emits DropProperty { Soft } by default.
5. Apply path implements Soft mode.
6. Convert PR #62 destructive-rejection tests.
7. --allow-data-loss flag + Hard mode.
8. (optional) Tombstone unhide / restore command.
Delete the planning doc when v1 lands. Intentionally checked in to
the WIP branch so the scope is reviewable; not intended as a
permanent doc.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Second commit of the chassis v1 branch. Lands the type-level shape
of soft/hard drops without wiring them up. Variants are reachable
from emitters but the planner doesn't produce them yet; the apply
path returns an explicit not-yet-implemented error if one shows up
via deserialization.
Added:
- `DropMode { Soft, Hard }` — orthogonal to `SafetyTier`. Tier
classifies the rule's risk class; mode is the operator's intent
for data treatment.
- `Soft` → catalog tombstone, data retained. Tier: safe.
- `Hard` → Lance-level removal. Tier: destructive; will require
--allow-data-loss to apply (commit 7).
- `SchemaMigrationStep::DropType { type_kind, name, mode }` and
`SchemaMigrationStep::DropProperty { type_kind, type_name,
property_name, mode }` variants.
- Re-export `DropMode` from `omnigraph_compiler::DropMode` so
downstream crates don't reach into the catalog submodule.
- CLI `render_schema_plan_step` arms for both variants, surfacing
the mode in plan output: `drop property 'Person.age' of node
'Person' (soft mode)`.
- `apply_schema_with_lock` exhaustive match arm for the two new
variants that returns `manifest_internal` with a clear
not-yet-implemented message. If a SchemaIR JSON containing
Drop{Type,Property} arrives (e.g. from a future tool or hand-
written), the apply path fails explicitly rather than silently
misclassifying.
- Two new in-source tests:
- `drop_steps_round_trip_through_serde` — pins the wire shape
for all four (variant × mode) combinations.
- `drop_mode_serde_uses_snake_case` — pins external-tool-
friendly serialization (`"soft"` / `"hard"`).
Build: clean, only pre-existing warnings.
Tests:
- omnigraph-compiler schema_plan: 6/6 (4 existing + 2 new).
- omnigraph-engine schema_apply: 11/11 (unchanged — planner still
emits UnsupportedChange for removal paths).
Next commit (commit 3 per docs/schema-lint-v1-plan.md): add the
`tombstoned: bool` fields to NodeIR / EdgeIR / PropertyIR for the
catalog representation of soft-mode tombstones.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After a substrate audit of the Lance data-evolution guide on 2026-05-13, the v1 plan was simplified. Two key findings: 1. Lance's `drop_columns()` is already metadata-only and reversible via time travel until cleanup. No need for a parallel `tombstoned: bool` field in our catalog IR — Lance's version graph IS the tombstone. 2. The full schema_apply substrate migration (add_columns, drop_columns, alter_columns vs. stage_overwrite across all step types) is consolidated in MR-948 as a sibling issue. v1 only uses the relevant slice (drop_columns for OG-DS-1XX). Net plan changes: - Commit 3 (original): tombstone fields on catalog IR → dropped. No catalog IR change needed. The Lance drop_columns commit IS the tombstone. - Commit 5 (original): apply path writes tombstoned: true → replaced with: apply path calls Dataset::drop_columns([name]). - Commit 7 Hard mode: stage_overwrite removing the column → replaced with: drop_columns + compact_files + cleanup_old_versions. Same APIs omnigraph cleanup already uses. - Commit 8 (original): omnigraph schema unhide → dropped. Time travel is the undo (omnigraph snapshot --at <commit>). Net result: 8 commits → 5 commits. ~250 LoC less surface. More substrate-aligned. The chassis types from commit 2 (DropMode enum, DropType / DropProperty variants) are kept exactly as designed; only the implementation strategy changed. The Lance docs quote is included in the doc so future readers see the substrate behavior cited verbatim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wire the dormant DropProperty variant end-to-end for the Soft case. Per docs/schema-lint-v1-plan.md, commit #3 of the schema-lint chassis v1 series (MR-694). Planner (schema_plan.rs): - plan_properties: emit DropProperty { type_kind, type_name, property_name, mode: Soft } instead of UnsupportedChange when a property exists in accepted but not in desired. Plan is now supported = true for drop-only changes. Apply (schema_apply.rs): - Route DropProperty { Soft } through rewritten_tables. The existing batch_for_schema_apply_rewrite path already iterates the *target* schema fields, so a property absent from desired_catalog is naturally projected away. The prior Lance version retains the dropped column for time-travel reversibility (until cleanup runs). - DropType still errors (lands in commit #4 with different mechanics: __manifest entry removal instead of column projection). - DropProperty { Hard } still errors (lands in commit #5 with --allow-data-loss CLI flag + immediate compact_files + cleanup_old_versions). Tests: - Planner unit test plan_emits_soft_drop_for_removed_nullable_property asserts the variant emission + supported = true + no UnsupportedChange. - Integration test apply_schema_drops_a_nullable_property_softly_ preserves_prior_version (replaces the former apply_schema_rejects_dropping_a_property_with_data) asserts: (a) plan contains DropProperty { Soft } (b) apply succeeds + manifest advances + row count unchanged (c) current dataset schema lacks the dropped column (d) snapshot_at_version(pre_drop) still has the dropped column (e) reopen consistency — drop preserved across engine restart Recovery: rides on SidecarKind::SchemaApply per MR-847. No new sidecar kind needed; the entire apply path is already sidecar-wrapped. Substrate alignment: this commit uses the stage_overwrite full-rewrite path (full_rewrite cost class) rather than Lance native drop_columns (catalog_only cost class). MR-948 is the follow-up substrate-alignment refactor that introduces a LanceColumnOp surface and switches the metadata-only case onto drop_columns. Functional outcome is identical; cost-class improvement deferred. Test results: - cargo test -p omnigraph-compiler --lib: 238 passed - cargo test -p omnigraph-engine --test schema_apply: 11 passed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Post-rebase fixup for the docs split (#93). The plan doc was added to docs/ at the top level before main reorganized to docs/{user,dev}/. This moves it into docs/dev/ and adds an entry to docs/dev/index.md under a new "Active Implementation Plans" section so the check-agents-md.sh link check passes. Per the original commit message (617a77d), the plan doc is intentionally temporary — it will be deleted when v1 lands. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
c74f524 to
2b468b9
Compare
There was a problem hiding this comment.
cubic analysis
4 issues found across 8 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="crates/omnigraph-compiler/src/catalog/schema_plan.rs">
<violation number="1" location="crates/omnigraph-compiler/src/catalog/schema_plan.rs:93">
P3: Custom agent: **Flag AI Slop and Fabricated Changes**
Comments reference nonexistent docs path `docs/schema-lint-v1-plan.md` instead of `docs/dev/schema-lint-v1-plan.md`</violation>
<violation number="2" location="crates/omnigraph-compiler/src/catalog/schema_plan.rs:156">
P2: `diagnostic()` does not map `DropProperty` to a stable code, so soft-drop steps lose code-tagged lint metadata (e.g., OG-DS-104) needed for MR-694-style severity/suppression and plan diagnostics.</violation>
</file>
<file name="docs/dev/schema-lint-v1-plan.md">
<violation number="1" location="docs/dev/schema-lint-v1-plan.md:36">
P2: This plan line reintroduces a `__manifest` tombstone for `DropType { Soft }`, which conflicts with the substrate-aligned approach. According to linked Linear issue MR-694, drop reversibility should rely on Lance version history rather than a new catalog tombstone field.</violation>
</file>
<file name="crates/omnigraph-cli/src/main.rs">
<violation number="1" location="crates/omnigraph-cli/src/main.rs:1048">
P2: According to linked Linear issue MR-694, schema plan output should surface code-tagged/classified diagnostics per step, but the new `DropProperty` output only shows `(soft mode)` and omits code/tier.</violation>
</file>
Linked issue analysis
Linked issue: MR-694: Schema-lint chassis: classification tuple + per-rule severity + suppression + pre-migration checks
| Status | Acceptance criteria | Notes |
|---|---|---|
| ✅ | Introduce DropMode enum and DropType / DropProperty variants on SchemaMigrationStep | The PR adds a DropMode enum (soft/hard) and the DropType/DropProperty variants with serde-stable wire shape so future consumers can deserialize them. |
| ✅ | Planner emits DropProperty { Soft } for removed nullable property | Planner now pushes DropProperty { Soft } instead of UnsupportedChange when a property is removed, and a unit test asserts the plan contains that step. |
| ✅ | Apply path handles DropProperty { Soft } via existing rewrite path (and rejects Hard/DropType as not-yet-implemented) | apply_schema match-arm routes Soft drops through the rewritten_tables/stage_overwrite flow; Hard mode and DropType still return a manifest_internal error as documented. Integration test verifies apply succeeds and time-travel semantics. |
| ✅ | CLI plan output renders code-tagged diagnostics and shows tier / drop-mode in plan lines | CLI rendering was extended to render DropProperty/DropType text and to show a step's diagnostic code and tier when present via the diagnostic() helper. |
| ✅ | Provide diagnostic() helper to surface DiagnosticCode (code, family, tier, default severity) for code-attached steps | SchemaMigrationStep::diagnostic() returns the catalog entry for steps carrying a schema-lint code and is used by CLI rendering to annotate plans with tier and code. |
| ✅ | Tests and docs updated to reflect the shipped slice (planner unit tests, integration tests, and in-repo plan doc) | The PR adds/preserves unit and integration tests that assert planner emission and successful apply semantics for soft drops; docs include an in-repo v1 plan and index entry listing the active plan. |
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Re-trigger cubic
| - [ ] In `plan_properties`'s leftover-property branch: emit `DropProperty { Soft }` instead of `UnsupportedChange` for OG-DS-104. | ||
| - [ ] Same for node-type removal (`plan_nodes` leftover → `DropType { Soft }`, OG-DS-102) and edge-type removal (`plan_edges` leftover → `DropType { Soft }`, OG-DS-103). | ||
| - [ ] `apply_schema_with_lock` handles `DropProperty { Soft }`: calls `Dataset::drop_columns(&[property_name])` and commits via the staged-write path. **Substrate primitive: Lance metadata-only commit.** | ||
| - [ ] `apply_schema_with_lock` handles `DropType { Soft }`: marks the table tombstoned in `__manifest` (data files retained). Reversible via branch / snapshot restore. |
There was a problem hiding this comment.
P2: This plan line reintroduces a __manifest tombstone for DropType { Soft }, which conflicts with the substrate-aligned approach. According to linked Linear issue MR-694, drop reversibility should rely on Lance version history rather than a new catalog tombstone field.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/dev/schema-lint-v1-plan.md, line 36:
<comment>This plan line reintroduces a `__manifest` tombstone for `DropType { Soft }`, which conflicts with the substrate-aligned approach. According to linked Linear issue MR-694, drop reversibility should rely on Lance version history rather than a new catalog tombstone field.</comment>
<file context>
@@ -0,0 +1,86 @@
+- [ ] In `plan_properties`'s leftover-property branch: emit `DropProperty { Soft }` instead of `UnsupportedChange` for OG-DS-104.
+- [ ] Same for node-type removal (`plan_nodes` leftover → `DropType { Soft }`, OG-DS-102) and edge-type removal (`plan_edges` leftover → `DropType { Soft }`, OG-DS-103).
+- [ ] `apply_schema_with_lock` handles `DropProperty { Soft }`: calls `Dataset::drop_columns(&[property_name])` and commits via the staged-write path. **Substrate primitive: Lance metadata-only commit.**
+- [ ] `apply_schema_with_lock` handles `DropType { Soft }`: marks the table tombstoned in `__manifest` (data files retained). Reversible via branch / snapshot restore.
+- [ ] Recovery sidecar: standard `catalog_only` discipline — the Lance commit IS the recoverable unit.
+- [ ] CLI plan output renders the new variants with mode visible.
</file context>
| - [ ] `apply_schema_with_lock` handles `DropType { Soft }`: marks the table tombstoned in `__manifest` (data files retained). Reversible via branch / snapshot restore. | |
| - [ ] `apply_schema_with_lock` handles `DropType { Soft }`: removes the type from the current manifest view while retaining prior Lance versions (data files retained) for time-travel restore. Reversible via branch / snapshot restore. |
| Self::UnsupportedChange { | ||
| code: Some(c), .. | ||
| } => crate::lint::lookup(c), | ||
| _ => None, |
There was a problem hiding this comment.
P2: diagnostic() does not map DropProperty to a stable code, so soft-drop steps lose code-tagged lint metadata (e.g., OG-DS-104) needed for MR-694-style severity/suppression and plan diagnostics.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/omnigraph-compiler/src/catalog/schema_plan.rs, line 156:
<comment>`diagnostic()` does not map `DropProperty` to a stable code, so soft-drop steps lose code-tagged lint metadata (e.g., OG-DS-104) needed for MR-694-style severity/suppression and plan diagnostics.</comment>
<file context>
@@ -93,6 +138,24 @@ impl SchemaMigrationStep {
+ Self::UnsupportedChange {
+ code: Some(c), ..
+ } => crate::lint::lookup(c),
+ _ => None,
+ }
+ }
</file context>
| _ => None, | |
| Self::DropProperty { .. } => Some(&crate::lint::codes::OG_DS_104), | |
| _ => None, |
| name, | ||
| drop_mode_label(*mode), | ||
| ), | ||
| SchemaMigrationStep::DropProperty { |
There was a problem hiding this comment.
P2: According to linked Linear issue MR-694, schema plan output should surface code-tagged/classified diagnostics per step, but the new DropProperty output only shows (soft mode) and omits code/tier.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/omnigraph-cli/src/main.rs, line 1048:
<comment>According to linked Linear issue MR-694, schema plan output should surface code-tagged/classified diagnostics per step, but the new `DropProperty` output only shows `(soft mode)` and omits code/tier.</comment>
<file context>
@@ -1035,14 +1035,48 @@ fn render_schema_plan_step(step: &SchemaMigrationStep) -> String {
+ name,
+ drop_mode_label(*mode),
+ ),
+ SchemaMigrationStep::DropProperty {
+ type_kind,
+ type_name,
</file context>
| /// requires `--allow-data-loss`. | ||
| /// | ||
| /// Dormant in this commit — emitted by the planner in a later | ||
| /// commit (see `docs/schema-lint-v1-plan.md`). |
There was a problem hiding this comment.
P3: Custom agent: Flag AI Slop and Fabricated Changes
Comments reference nonexistent docs path docs/schema-lint-v1-plan.md instead of docs/dev/schema-lint-v1-plan.md
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/omnigraph-compiler/src/catalog/schema_plan.rs, line 93:
<comment>Comments reference nonexistent docs path `docs/schema-lint-v1-plan.md` instead of `docs/dev/schema-lint-v1-plan.md`</comment>
<file context>
@@ -62,6 +85,28 @@ pub enum SchemaMigrationStep {
+ /// requires `--allow-data-loss`.
+ ///
+ /// Dormant in this commit — emitted by the planner in a later
+ /// commit (see `docs/schema-lint-v1-plan.md`).
+ DropType {
+ type_kind: SchemaTypeKind,
</file context>
| /// commit (see `docs/schema-lint-v1-plan.md`). | |
| + /// commit (see `docs/dev/schema-lint-v1-plan.md`). |
| steps.push(SchemaMigrationStep::DropProperty { | ||
| type_kind, | ||
| type_name: type_name.to_string(), | ||
| property_name: leftover.name.clone(), | ||
| mode: DropMode::Soft, | ||
| }); |
There was a problem hiding this comment.
🔴 DropProperty on interfaces crashes apply with 'missing source table' because interfaces have no Lance dataset
The plan_properties function is called for interfaces (schema_plan.rs:197), and the leftover-property branch now emits DropProperty { type_kind: Interface, ... } at schema_plan.rs:576-581. In the apply path at schema_apply.rs:162, this produces table key "interface:<Name>" and inserts it into rewritten_tables. However, interfaces are schema-level constructs with no Lance dataset or manifest entry. When the rewrite loop at schema_apply.rs:365 calls snapshot.entry("interface:..."), it returns None and the apply fails with a confusing "missing source table 'interface:...' for schema apply" error.
Under the old code, interface property removal emitted UnsupportedChange, so supported was false and the apply was rejected before reaching the rewrite loop. The new DropProperty { Soft } bypasses the supported check (schema_plan.rs:176-178 only checks for UnsupportedChange), allowing apply to proceed into the crash. Any schema migration that removes a property from an interface will hit this.
Prompt for agents
The plan_properties function is called for interfaces (SchemaTypeKind::Interface) at plan_interfaces (schema_plan.rs:197). When a property is removed from an interface, the leftover branch now emits DropProperty { type_kind: Interface, ... }. But the apply path in schema_apply.rs treats DropProperty by adding the table key to rewritten_tables — and interfaces have no Lance dataset or manifest entry, so the rewrite loop fails with 'missing source table'.
Two possible fixes:
1. In the leftover-property branch of plan_properties (around line 576), check if type_kind is Interface and emit UnsupportedChange instead of DropProperty for interface properties. This preserves the old behavior for interfaces while allowing node/edge property drops.
2. In the apply path's DropProperty handler in schema_apply.rs (around line 141), skip adding to rewritten_tables when type_kind is Interface, since interfaces don't have physical datasets. Interface property drops would be a catalog-only change.
Option 1 is safer for now since interface property semantics are inherited by implementing nodes, and dropping an interface property has cascading effects on all implementing node types that would also need handling.
Was this helpful? React with 👍 or 👎 to provide feedback.
| steps.push(SchemaMigrationStep::DropProperty { | ||
| type_kind, | ||
| type_name: type_name.to_string(), | ||
| property_name: leftover.name.clone(), | ||
| mode: DropMode::Soft, | ||
| }); |
There was a problem hiding this comment.
🔴 User-facing schema-lint docs not updated after property-drop behavior change (AGENTS.md Rule 1 violation)
docs/user/schema-lint.md:10 says [OG-DS-104] removing property 'Person.age' is not supported … appears in error messages, and line 34 lists OG-DS-104 as an error that blocks apply. After this PR's change, property drops now succeed via DropProperty { Soft } — OG-DS-104 is no longer emitted at all. AGENTS.md Rule 1 states: "New endpoint, query function, CLI flag, env var, constant, schema construct, or invariant: update both the source code and the doc in the same change. Never split documentation drift into a follow-up." This is a user-visible behavioral change (property drops went from rejected to allowed) without a corresponding doc update.
Prompt for agents
The behavioral change at schema_plan.rs:576-581 means property drops are now allowed (soft mode) instead of rejected with OG-DS-104. The following user-facing docs need updating in this same PR:
1. docs/user/schema-lint.md line 10: The example error message '[OG-DS-104] removing property ...' no longer appears because the operation now succeeds. Update to describe the new soft-drop behavior.
2. docs/user/schema-lint.md line 34: The OG-DS-104 row should note it is no longer emitted for property drops (or update to reflect that soft drops are now the default behavior).
3. docs/user/schema-language.md line 78: The list of SchemaMigrationStep variants only mentions UnsupportedChange. Add DropProperty (and DropType as dormant).
4. crates/omnigraph-compiler/src/lint/codes.rs line 119: EMITTED_IN_V0 includes 'OG-DS-104' which is no longer emitted as an UnsupportedChange code. Remove it from the list or rename the constant to reflect the current state.
Was this helpful? React with 👍 or 👎 to provide feedback.
| ## Done in this branch so far | ||
|
|
||
| - [x] **Commit 1** — `SchemaMigrationStep::diagnostic()` helper + CLI plan output displays tier alongside the code: `unsupported change on node:Person.age [OG-DS-104, destructive]: ...`. No behavior change. All 11 existing `schema_apply` tests still pass. | ||
| - [x] **Commit 2** — `DropMode { Soft, Hard }` enum + dormant `DropType` and `DropProperty` variants on `SchemaMigrationStep`. Apply path has an exhaustive-match arm returning `manifest_internal` if either variant arrives via deserialization. Serde round-trip pinned for stable wire shape. |
There was a problem hiding this comment.
🟡 Plan doc claims DropProperty is 'dormant' and 'No behavior change' but code actively implements soft property drops
The plan document added in this PR states at line 25: "Commit 2 — … dormant DropType and DropProperty variants … No behavior change." However, the code in this same PR actively emits DropProperty { Soft } from the planner (schema_plan.rs:576-581) and handles it in the apply path (schema_apply.rs:141-167). Additionally, line 33 marks "emit DropProperty { Soft } instead of UnsupportedChange" as unchecked future work ([ ]) under commit 3, but it is already implemented. Per AGENTS.md Rule 6: "Don't lie. If a section becomes wrong but you can't rewrite it fully right now, replace the wrong line with (stale — needs update) rather than leaving silently incorrect text."
Prompt for agents
The 'Done in this branch so far' section at line 25 says commit 2 adds 'dormant' DropProperty variants with 'No behavior change', but the code actually implements DropProperty { Soft } end-to-end (planner emits it, apply handles it). Update the 'Done' section to reflect that commit 2 also includes the planner change for DropProperty and the soft-drop apply path. Move the checked items from commit 3 (line 33: plan_properties leftover branch change, apply path DropProperty handling) into the 'Done' section, or merge commits 2 and 3 in the plan description.
Was this helpful? React with 👍 or 👎 to provide feedback.
Wire the second half of the dormant Drop* family. Per docs/dev/schema-lint-v1-plan.md, commit #4 of the schema-lint chassis v1 series (MR-694). Builds on commit #3 (PR #90, DropProperty Soft). Planner (schema_plan.rs): - plan_nodes leftover loop: emit DropType { Node, name, Soft } instead of UnsupportedChange (OG-DS-102) for node-type removals. - plan_edges leftover loop: emit DropType { Edge, name, Soft } instead of UnsupportedChange (OG-DS-103) for edge-type removals. Apply (schema_apply.rs): - New dropped_tables: BTreeSet<String> accumulator alongside added_tables / renamed_tables / rewritten_tables. - DropType arm in the metadata loop populates dropped_tables for Soft mode. Hard mode errors (lands in commit #5 with --allow-data-loss). - New tombstone-emission loop after the rename sidecar build: for each dropped table, push to sidecar_tombstones AND populate table_tombstones with table_version + 1. The existing manifest publish path converts table_tombstones into ManifestChange::Tombstone operations — no new manifest plumbing needed. - Soft DropType has no Phase B per-table write; the tombstone is the entire change. Lance dataset files are retained — prior __manifest versions still reference them, so time travel + branch-from-snapshot can read the dropped table until cleanup_old_versions runs. - Rides on SidecarKind::SchemaApply per MR-847 (already established by commit #3). Tests: - Planner unit test plan_emits_soft_drop_for_removed_node_and_edge_types asserts both Node and Edge DropType { Soft } emission for the Company + WorksAt combined drop, plus no UnsupportedChange. - Integration test apply_schema_drops_node_and_referencing_edge_softly (replaces apply_schema_rejects_dropping_a_node_type): asserts plan emission, apply success, current manifest entries absent, pre-drop manifest entries present (time-travel reversibility), reopen consistency. - Integration test apply_schema_drops_an_edge_type_softly (replaces apply_schema_rejects_dropping_an_edge_type): single edge drop, asserts other tables untouched, time-travel reversibility. Test results: - cargo test -p omnigraph-compiler --lib: 239 passed (1 new + 238) - cargo test -p omnigraph-engine --test schema_apply: 11 passed (2 converted + 9 unchanged) Pending for v1 completion: - Commit #5: --allow-data-loss CLI flag + Hard mode promotion in planner + immediate compact_files + cleanup_old_versions for both DropProperty and DropType. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Summary
Schema-lint chassis v1.0. Builds on v0 (PR #87) by wiring DropProperty { Soft } end-to-end — operators can now remove a nullable property from a
.pgschema andomnigraph schema applywill succeed, dropping the column from the current manifest version while preserving it in prior versions for time-travel reversibility (untilomnigraph cleanupruns).Doesn't include DropType (commit #4 — separate PR) or Hard mode +
--allow-data-loss(commit #5 — separate PR). Soft mode is non-destructive by design and ships independently.What lands
Planner (
schema_plan.rs):DropMode { Soft, Hard }enum +DropType/DropPropertyvariants onSchemaMigrationStep(Hard + DropType remain dormant; only DropProperty Soft is emitted).plan_propertiesemitsDropProperty { Soft }for property removals instead ofUnsupportedChange.SchemaMigrationStep::diagnostic()helper returning the fullDiagnosticCodecatalog entry (family, tier, default severity) for code-tagged steps.Apply (
schema_apply.rs):DropProperty { Soft }routes through the existingrewritten_tablespath.batch_for_schema_apply_rewriteiterates target schema fields, so the dropped column is naturally projected away."DropType not yet implemented (commit #4)"."DropProperty { Hard } not yet implemented (commit #5)".SidecarKind::SchemaApplyrecovery discipline per MR-847 — no new sidecar kind.CLI (
omnigraph-cli):drop property 'X' (soft mode)with tier annotation.[OG-XX-NNN, tier] reason.Docs:
docs/dev/schema-lint-v1-plan.md(working doc for the v1 series — will be removed when commit Add schema apply command and policy support #5 lands).docs/dev/index.mdunder "Active Implementation Plans".Tests:
plan_emits_soft_drop_for_removed_nullable_property.apply_schema_drops_a_nullable_property_softly_preserves_prior_version(5 assertions: plan emission, apply success, current column absent, prior-version column present, reopen consistency).What's deliberately not in this PR
__manifestentry removal. Different mechanics from column drop. Commit Support multi-statement mutations (insert + edge in one query) #4.--allow-data-lossCLI flag, planner Soft→Hard upgrade when flag set, apply path runscompact_files+cleanup_old_versionsfor Hard. Commit Add schema apply command and policy support #5.drop_columns— current implementation usesstage_overwrite(O(rows) full rewrite). MR-948 is the substrate-alignment refactor that switches toDataset::drop_columns(O(catalog) metadata-only). Functional outcome is identical; cost-class optimization deferred.cost_classfield onDiagnosticCode— deferred per the v1 plan doc; tier-driven (--allow-data-loss) is the v1 mechanism, cost-driven gating is a later chassis extension.Test plan
cargo test -p omnigraph-compiler --lib— 238 passcargo test -p omnigraph-engine --test schema_apply— 11 pass (1 converted + 10 unchanged)scripts/check-agents-md.sh— 34 links / 33 docs OKtest.pg, apply, verify column gone from current snapshot + present insnapshot_at_version(pre_drop)+ reopen preserves stateFollow-ups (separate PRs)
--allow-data-lossflag (new PR after Support multi-statement mutations (insert + edge in one query) #4)stage_overwritetoDataset::drop_columns🤖 Generated with Claude Code