Skip to content

schema: HTTP allow_data_loss exposure + e2e drop coverage (MR-694 follow-up) - #107

Merged
aaltshuler merged 1 commit into
mainfrom
andrew/schema-migration-e2e-gap-fills
May 18, 2026
Merged

aaltshuler merged 1 commit into
mainfrom
andrew/schema-migration-e2e-gap-fills

Conversation

@aaltshuler

@aaltshuler aaltshuler commented May 18, 2026

Copy link
Copy Markdown
Contributor

Summary

PR B of the comprehensive e2e coverage plan. PR #106 closed the policy gaps; this PR closes the schema-migration gaps + the lingering HTTP feature gap from the schema-lint chassis v1.2.

The schema-lint chassis v1.2 (PR #100) shipped `--allow-data-loss` on the CLI, but `SchemaApplyRequest` had no equivalent field — Hard-mode drops were CLI-only. This PR closes that feature gap and adds e2e test coverage across HTTP + CLI for drop modes, data preservation, and CLI↔SDK plan parity.

Code change: HTTP `allow_data_loss` exposure

  • `SchemaApplyRequest.allow_data_loss: bool` (default false via `#[serde(default)]`) — operators can request Hard-mode drops via HTTP.
  • `server_schema_apply` threads the field into `SchemaApplyOptions` → `apply_schema_as`.
  • CLI remote-URI path drops its previous "--allow-data-loss is not yet supported on remote" bail and forwards the flag uniformly.
  • `openapi.json` regenerated (one new field).

Tests added (8 new)

HTTP (`omnigraph-server/tests/server.rs`)

  • `schema_apply_route_soft_drops_property_via_http` — POST drops nullable property; catalog reflects + `snapshot_at_version(pre)` keeps the column reachable.
  • `schema_apply_route_soft_drops_node_type_via_http` — POST drops `Company` node + cascading `WorksAt` edge.
  • `schema_apply_route_hard_drops_property_with_allow_data_loss` — POST with `allow_data_loss: true`, plan step reports `mode: hard`.
  • `schema_apply_route_keeps_drops_soft_without_flag` — same schema without flag → `mode: soft` (pins default semantics against accidental Hard promotion).
  • `schema_apply_route_additive_property_preserves_existing_rows` — closes the data-preservation gap on AddProperty (SDK suite covered drops + renames but not additive).

CLI (`omnigraph-cli/tests/cli.rs`)

  • `schema_apply_allow_data_loss_flag_promotes_drops_to_hard` — `omnigraph schema apply --allow-data-loss` → `mode: hard` in the plan step.
  • `schema_apply_without_allow_data_loss_keeps_soft_drops` — symmetric Soft case.
  • `schema_plan_parity_cli_and_sdk` — same `.pg` source through `Omnigraph::plan_schema` (SDK) and `omnigraph schema plan --json` (CLI) produces byte-identical step arrays. HTTP has no `/schema/plan` route; apply-side parity is implicitly covered by the HTTP drop tests using identical fixtures.

Docs

`docs/user/schema-language.md` gets a new "Destructive drops — `--allow-data-loss`" section documenting Soft vs Hard semantics and uniform behavior across CLI / HTTP / SDK.

Test plan

  • `cargo test -p omnigraph-server --test server -- schema_apply_route` — all green (existing + 5 new)
  • `cargo test -p omnigraph-server --test openapi` — green (openapi.json regenerated cleanly)
  • `cargo test -p omnigraph-cli --test cli -- schema_apply schema_plan` — green (existing + 3 new)
  • `cargo test --workspace --locked` — green
  • `scripts/check-agents-md.sh` — passes

🤖 Generated with Claude Code


Open in Devin Review

@aaltshuler
aaltshuler requested a review from ragnorc as a code owner May 18, 2026 18:20

@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

2 issues found across 7 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="docs/user/schema-language.md">

<violation number="1" location="docs/user/schema-language.md:86">
P2: Custom agent: **Flag AI Slop and Fabricated Changes**

Docs overstate hard-drop guarantee: claims data becomes 'unreachable' and 'Irreversible' but implementation has best-effort cleanup that can fail silently (per MR-694).</violation>
</file>

<file name="crates/omnigraph-server/tests/server.rs">

<violation number="1" location="crates/omnigraph-server/tests/server.rs:4026">
P3: Custom agent: **Flag AI Slop and Fabricated Changes**

The "without flag" test still sends `allow_data_loss: false` explicitly, so it does not validate the new default-false HTTP deserialization behavior.</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
Add allow_data_loss field to HTTP SchemaApplyRequest (default false via serde) SchemaApplyRequest now includes an allow_data_loss: bool field with #[serde(default)] and Default impl on the struct, matching the claimed API change.
Thread allow_data_loss into server apply path (SchemaApplyOptions) server_schema_apply forwards request.allow_data_loss into SchemaApplyOptions when calling db.apply_schema_as, so the server honors the HTTP flag.
CLI remote path forwards --allow-data-loss instead of bailing CLI removed the previous bail for remote apply and includes allow_data_loss in the JSON payload sent to /schema/apply.
OpenAPI updated to include allow_data_loss openapi.json contains the new allow_data_loss boolean property and description matching the change.
End-to-end tests: HTTP tests cover soft vs hard drops, data preservation, and CLI tests cover flag promotion and plan parity Multiple new tests were added in server and CLI test files that assert soft drops preserve prior-version access, allow_data_loss=true promotes drops to hard, default keeps soft, additive property preserves rows, and CLI/SDK plan parity is byte-identical.
Docs updated to document Soft vs Hard semantics and transports docs/user/schema-language.md was updated with a Destructive drops section describing --allow-data-loss and uniform behavior across CLI/HTTP/SDK.

Reply with feedback, questions, or to request a fix.

Re-trigger cubic


`DropProperty` and `DropType` steps default to `Soft` mode: the catalog tombstones the entry but the prior column / dataset remains time-travel-reachable via `snapshot_at_version(prev)` until `omnigraph cleanup` runs. Soft drops are reversible.

Pass `--allow-data-loss` (CLI) or `allow_data_loss: true` (HTTP `POST /schema/apply` body, SDK `SchemaApplyOptions`) to promote every drop in the plan to `Hard` mode. Hard drops run `cleanup_old_versions` on the affected dataset immediately after the manifest publish, making the prior column / dataset unreachable. **Irreversible.**

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: Custom agent: Flag AI Slop and Fabricated Changes

Docs overstate hard-drop guarantee: claims data becomes 'unreachable' and 'Irreversible' but implementation has best-effort cleanup that can fail silently (per MR-694).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/user/schema-language.md, line 86:

<comment>Docs overstate hard-drop guarantee: claims data becomes 'unreachable' and 'Irreversible' but implementation has best-effort cleanup that can fail silently (per MR-694).</comment>

<file context>
@@ -78,3 +78,11 @@ Edge bodies only allow `@unique` and `@index`.
+
+`DropProperty` and `DropType` steps default to `Soft` mode: the catalog tombstones the entry but the prior column / dataset remains time-travel-reachable via `snapshot_at_version(prev)` until `omnigraph cleanup` runs. Soft drops are reversible.
+
+Pass `--allow-data-loss` (CLI) or `allow_data_loss: true` (HTTP `POST /schema/apply` body, SDK `SchemaApplyOptions`) to promote every drop in the plan to `Hard` mode. Hard drops run `cleanup_old_versions` on the affected dataset immediately after the manifest publish, making the prior column / dataset unreachable. **Irreversible.**
+
+The flag is honored uniformly across transports — `omnigraph schema apply --allow-data-loss`, `POST /schema/apply { schema_source, allow_data_loss: true }`, and `apply_schema_with_options(.., SchemaApplyOptions { allow_data_loss: true })` produce identical plans and identical effects.
</file context>

.body(Body::from(
serde_json::to_vec(&SchemaApplyRequest {
schema_source: schema_without_age(),
allow_data_loss: false,

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

The "without flag" test still sends allow_data_loss: false explicitly, so it does not validate the new default-false HTTP deserialization behavior.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/omnigraph-server/tests/server.rs, line 4026:

<comment>The "without flag" test still sends `allow_data_loss: false` explicitly, so it does not validate the new default-false HTTP deserialization behavior.</comment>

<file context>
@@ -3787,3 +3821,288 @@ async fn default_deny_mode_rejects_schema_apply_with_forbidden() {
+            .body(Body::from(
+                serde_json::to_vec(&SchemaApplyRequest {
+                    schema_source: schema_without_age(),
+                    allow_data_loss: false,
+                })
+                .unwrap(),
</file context>

@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: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

…low-up)

The schema-lint chassis v1.2 (PR #100) shipped `--allow-data-loss` on
the CLI, but `SchemaApplyRequest` had no equivalent field — Hard-mode
drops were CLI-only. This commit closes that feature gap and adds e2e
test coverage for drop modes across HTTP + CLI, plus data preservation
on additive apply, plus a CLI↔SDK plan-parity assertion.

Feature gap closed:

- `crates/omnigraph-server/src/api.rs` — added `allow_data_loss: bool`
  (default false via `#[serde(default)]`) to `SchemaApplyRequest`.
  Added `Default` derive so test usages can use `..Default::default()`.
- `crates/omnigraph-server/src/lib.rs` — `server_schema_apply` now
  constructs `SchemaApplyOptions { allow_data_loss: request.allow_data_loss }`
  and threads through to `apply_schema_as`.
- `crates/omnigraph-cli/src/main.rs` — remote-URI schema-apply path
  used to bail with "--allow-data-loss not yet supported on remote";
  now forwards the flag into the JSON payload so the CLI behaves
  identically against local and remote URIs.
- `openapi.json` — regenerated; only diff is the new field on
  `SchemaApplyRequest`.

Tests added (8 new):

* `crates/omnigraph-server/tests/server.rs` (+5):
  - `schema_apply_route_soft_drops_property_via_http` — POST schema
    removing nullable property, verify catalog reflects the drop AND
    `snapshot_at_version(pre)` still has `age` in the field list
    (time-travel reachability is the Soft contract).
  - `schema_apply_route_soft_drops_node_type_via_http` — POST schema
    removing `Company` node + cascading `WorksAt` edge.
  - `schema_apply_route_hard_drops_property_with_allow_data_loss` —
    POST with `allow_data_loss: true`, verify plan step reports
    `mode: hard`.
  - `schema_apply_route_keeps_drops_soft_without_flag` — same schema
    without flag, verify `mode: soft`. Pins default semantics against
    accidental Hard promotion.
  - `schema_apply_route_additive_property_preserves_existing_rows` —
    load fixture, POST adding nullable property, verify row count
    preserved (SDK suite covers data preservation on drops + renames;
    additive AddProperty wasn't pinned).
  Plus helpers `schema_without_age` and `schema_without_company`.

* `crates/omnigraph-cli/tests/cli.rs` (+3):
  - `schema_apply_allow_data_loss_flag_promotes_drops_to_hard` — CLI
    `omnigraph schema apply --allow-data-loss --schema X.pg --json`,
    verify plan step has `mode: hard`.
  - `schema_apply_without_allow_data_loss_keeps_soft_drops` — without
    flag, verify Soft.
  - `schema_plan_parity_cli_and_sdk` — same `.pg` source through
    `Omnigraph::plan_schema` (SDK) and `omnigraph schema plan --json`
    (CLI), assert the steps array is byte-identical post-JSON. HTTP
    has no `/schema/plan` endpoint; apply-side parity is implicitly
    covered by the HTTP drop tests + CLI drop tests using identical
    fixtures.

Docs:

- `docs/user/schema-language.md` — new "Destructive drops" section
  documenting Soft vs Hard semantics and that `allow_data_loss` is
  now honored uniformly across CLI / HTTP / SDK.

Verification: every new test passes; full `cargo test --workspace --locked`
green; `scripts/check-agents-md.sh` passes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@aaltshuler
aaltshuler force-pushed the andrew/schema-migration-e2e-gap-fills branch from 512bfed to c03de7e Compare May 18, 2026 19:28
@aaltshuler
aaltshuler merged commit aadfa11 into main May 18, 2026
6 checks passed
@aaltshuler
aaltshuler deleted the andrew/schema-migration-e2e-gap-fills branch May 18, 2026 22:56
@aaltshuler aaltshuler mentioned this pull request May 23, 2026
6 tasks
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