Skip to content

schema-lint chassis v1.0: DropProperty Soft + code-tagged diagnostics (MR-694) - #90

Merged
aaltshuler merged 5 commits into
mainfrom
andrew/mr-694-chassis-v1-allow-data-loss
May 16, 2026
Merged

schema-lint chassis v1.0: DropProperty Soft + code-tagged diagnostics (MR-694)#90
aaltshuler merged 5 commits into
mainfrom
andrew/mr-694-chassis-v1-allow-data-loss

Conversation

@aaltshuler

@aaltshuler aaltshuler commented May 13, 2026

Copy link
Copy Markdown
Contributor

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 .pg schema and omnigraph schema apply will succeed, dropping the column from the current manifest version while preserving it in prior versions for time-travel reversibility (until omnigraph cleanup runs).

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 / DropProperty variants on SchemaMigrationStep (Hard + DropType remain dormant; only DropProperty Soft is emitted).
  • plan_properties emits DropProperty { Soft } for property removals instead of UnsupportedChange.
  • SchemaMigrationStep::diagnostic() helper returning the full DiagnosticCode catalog entry (family, tier, default severity) for code-tagged steps.

Apply (schema_apply.rs):

  • DropProperty { Soft } routes through the existing rewritten_tables path. batch_for_schema_apply_rewrite iterates target schema fields, so the dropped column is naturally projected away.
  • DropType still errors with "DropType not yet implemented (commit #4)".
  • DropProperty Hard still errors with "DropProperty { Hard } not yet implemented (commit #5)".
  • Rides on existing SidecarKind::SchemaApply recovery discipline per MR-847 — no new sidecar kind.

CLI (omnigraph-cli):

  • Plan output renders drop property 'X' (soft mode) with tier annotation.
  • Unsupported steps render [OG-XX-NNN, tier] reason.

Docs:

Tests:

  • Planner unit test: plan_emits_soft_drop_for_removed_nullable_property.
  • Integration test: 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).
  • Existing destructive-rejection tests for DropType, narrow-type, required-without-backfill, edge-type-drop all preserved.

What's deliberately not in this PR

  • DropType Soft — whole-table drop via __manifest entry removal. Different mechanics from column drop. Commit Support multi-statement mutations (insert + edge in one query) #4.
  • Hard mode promotion--allow-data-loss CLI flag, planner Soft→Hard upgrade when flag set, apply path runs compact_files + cleanup_old_versions for Hard. Commit Add schema apply command and policy support #5.
  • Lance native drop_columns — current implementation uses stage_overwrite (O(rows) full rewrite). MR-948 is the substrate-alignment refactor that switches to Dataset::drop_columns (O(catalog) metadata-only). Functional outcome is identical; cost-class optimization deferred.
  • cost_class field on DiagnosticCode — 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 pass
  • cargo test -p omnigraph-engine --test schema_apply — 11 pass (1 converted + 10 unchanged)
  • scripts/check-agents-md.sh — 34 links / 33 docs OK
  • CI green on rebased branch (Test Workspace, Test omnigraph-server --features aws, Classify Changes, Check AGENTS.md Links)
  • Manual smoke: drop nullable property from test.pg, apply, verify column gone from current snapshot + present in snapshot_at_version(pre_drop) + reopen preserves state

Follow-ups (separate PRs)

🤖 Generated with Claude Code

@aaltshuler
aaltshuler force-pushed the andrew/mr-694-chassis-v1-allow-data-loss branch from 25064ca to 48ba696 Compare May 13, 2026 15:10
aaltshuler and others added 5 commits May 16, 2026 15:48
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>
@aaltshuler
aaltshuler force-pushed the andrew/mr-694-chassis-v1-allow-data-loss branch from c74f524 to 2b468b9 Compare May 16, 2026 13:14
@aaltshuler aaltshuler changed the title schema-lint chassis v1 (WIP): --allow-data-loss + soft/hard drops (MR-694) schema-lint chassis v1.0: DropProperty Soft + code-tagged diagnostics (MR-694) May 16, 2026
@aaltshuler
aaltshuler marked this pull request as ready for review May 16, 2026 13:29
@aaltshuler
aaltshuler requested a review from ragnorc as a code owner May 16, 2026 13:29
@aaltshuler
aaltshuler merged commit e98347e into main May 16, 2026
5 of 6 checks passed

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Suggested change
- [ ] `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,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Suggested change
_ => None,
Self::DropProperty { .. } => Some(&crate::lint::codes::OG_DS_104),
_ => None,

name,
drop_mode_label(*mode),
),
SchemaMigrationStep::DropProperty {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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`).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Suggested change
/// commit (see `docs/schema-lint-v1-plan.md`).
+ /// commit (see `docs/dev/schema-lint-v1-plan.md`).

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines +576 to 581
steps.push(SchemaMigrationStep::DropProperty {
type_kind,
type_name: type_name.to_string(),
property_name: leftover.name.clone(),
mode: DropMode::Soft,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 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.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +576 to 581
steps.push(SchemaMigrationStep::DropProperty {
type_kind,
type_name: type_name.to_string(),
property_name: leftover.name.clone(),
mode: DropMode::Soft,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 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.
Open in Devin Review

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

aaltshuler added a commit that referenced this pull request May 16, 2026
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>
@aaltshuler
aaltshuler deleted the andrew/mr-694-chassis-v1-allow-data-loss branch June 8, 2026 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant