Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Edit an output-port ODCS file under models/output_ports/v<N>/, run the contract test against the live data, and classify any failures as breaking or non-breaking changes — with suggested fixes. Only edits output-port contracts (the spec this data product commits to); input-port contracts under models/input_ports/ are upstream's responsibility and refreshed by dataproduct-implement. Trigger when the user asks to "add/remove/change a column in the data contract", "update the data contract", or "te
.claude/skills/hashgraph-online-datacontract-edit/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 1096% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 158% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 20% | 0% |
| case-19 | ✗→✓ | ▲ Improved | 167% | 0% |
| case-22 | ✗→✓ | ▲ Improved | 47% | 0% |
Change an output-port models/output_ports/v<N>/*.odcs.yaml file, run the contract test, and tell the user whether the change breaks consumers.
This skill operates only on output-port contracts — the spec this data product commits to. Input-port contracts under models/input_ports/ are cached snapshots of upstream's spec and are not editable here; if you want to refresh one (because upstream changed it), run dataproduct-implement instead.
> ${PLUGIN_ROOT} below refers to the root of this plugin — the directory that contains skills/. On Claude Code it is set automatically as ${CLAUDE_PLUGIN_ROOT} — use that. On any other agent (Codex, Copilot CLI, etc.) it is unset; resolve it as ../.. relative to this SKILL.md file's directory (i.e. the grandparent of skills/<this-skill>/).
Before running Step 0, print this plan to the user verbatim:
> Running datacontract-edit. I'll: > 1. Locate the output-port contract file under models/output_ports/v<N>/ that matches your request. > 2. Apply the edit in place and show you a unified diff. > 3. Run datacontract test against the live server to check the change. > 4. Classify each failure as breaking-schema, breaking-quality, additive, or unrelated. > 5. Report and suggest concrete fixes (no version bump, no v2 directory, no dbt model changes).
Then proceed.
models/output_ports/**/*.odcs.yaml — never models/input_ports/. If the user names an input-port contract, stop and explain it can't be edited here (refresh via dataproduct-implement instead).models/output_ports/.models block as BEFORE.Edit the ODCS YAML in place using the user's instruction. Keep the change minimal — do not reformat unrelated fields.
Common edits and the right shape:
| User says | What to change | |---|---| | "add column X" | Append a field under the relevant model with at least type; set required: false by default unless the user says it's required | | "remove column X" | Delete the field; this is breaking — flag in Step 4 | | "rename X to Y" | Rename the field; this is breaking — flag | | "make X required" | Add required: true; breaking if existing rows can be null | | "change X type from int to string" | Update type; breaking unless the new type is a strict superset (e.g. int → bigint) | | "add a unique/not_null/enum check" | Add to the field's quality rules; breaking iff existing data violates the new rule — only Step 2 can tell |
After editing, remember the new models block as AFTER and show the user a unified diff before continuing.
Run the test with the datacontract CLI against the local contract file:
datacontract test models/output_ports/v<N>/<file>.odcs.yaml --server <server> --logsproduction). Default to all only if the user explicitly asks.--logs so failure detail is in the output you read; otherwise the CLI only prints a summary.--output ./test-results/junit.xml --output-format junit.TEST_RESULT. Non-zero exit means at least one rule failed; the log section names the failing field/rule.Pre-reqs the CLI needs (verify before running, fail fast with a clear message if missing):
uv run --quiet datacontract --version succeeds from the project root. If it fails, run uv sync and retry. Invoke as uv run datacontract test … for every CLI invocation in this skill.DATACONTRACT_SNOWFLAKE_USERNAME / ..._PASSWORD, or DATACONTRACT_DATABRICKS_TOKEN). Tell the user which env vars are missing — do not try to source them yourself.Do not use the platform's server-side contract-test endpoint from this skill. The local datacontract CLI runs against the edited file and gives line-level failure detail; testing the published version on the server would test the previous contract, which defeats the point of testing the edit.
Group every failure into one of these buckets:
| Bucket | Examples | Severity | |---|---|---| | Breaking — schema | column removed, type narrowed, column renamed | High — bump major version, deprecate old port | | Breaking — quality | new not_null/unique/enum rule violated by existing data | High — clean data first, then re-test | | Non-breaking — additive | new optional column, widened type, loosened rule | Low — minor version bump | | Test failure unrelated to the edit | flaky source, infra error, unchanged rule failing | Investigate separately |
For each failure, name the exact field/rule and which bucket it falls into. Don't lump them together.
End with this two-part recap. The Status column uses the shared enum (created, updated, already present, deferred, skipped), and below it a classification table covers any test failures.
Part 1 — outcome table.
| Artifact | Status | Details | |---|---|---| | Contract file | updated | models/output_ports/v<N>/<file>.odcs.yaml — show the unified diff inline | | Contract test | … | pass, fail (<N> failures), or not run (missing creds) — name the server | | Breaking — schema | … | count of failures in this bucket, or "—" | | Breaking — quality | … | count of failures in this bucket, or "—" | | Non-breaking — additive | … | count of changes in this bucket, or "—" | | Test failures unrelated to the edit | … | count, or "—" | | Recommended version bump | … | patch / minor / major based on the edit |
For the four "bucket" rows, leave Status = — and put the failure count + a one-line bucket description in Details.
Part 2 — next steps. Per failure, give a concrete fix suggestion:
models/output_ports/v2/), keep v1 alive, add a deprecation note in <id>.odps.yaml.version minor, no consumer impact.Do not auto-bump the contract version, do not create v2/ directories, and do not modify dbt models. Surface the recommendation; let the user decide.
dataproduct-implement after this skill.entropy-data datacontracts get <id> -o yaml redirected to the file).| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 29,233 | 8,937 | -69% | 1 | 1 | 0% | 2,068 | 2,480 | +20% | 0 | 0 | — |
case-02 | fail→fail | 16,790 | 4,506 | -73% | 1 | 1 | 0% | 3,050 | 2,730 | -10% | 0 | 0 | — |
case-03 | fail→fail | 10,771 | 9,001 | -16% | 1 | 1 | 0% | 202 | 2,471 | +1123% | 0 | 0 | — |
case-04 | fail→pass | 15,660 | 9,361 | -40% | 1 | 1 | 0% | 235 | 2,810 | +1096% | 0 | 0 | — |
case-05 | fail→fail | 13,418 | 18,449 | +37% | 1 | 1 | 0% | 1,100 | 2,743 | +149% | 0 | 0 | — |
case-06 | fail→fail | 10,009 | 10,449 | +4% | 1 | 1 | 0% | 512 | 2,851 | +457% | 0 | 0 | — |
case-07 | fail→fail | 11,365 | 8,169 | -28% | 1 | 1 | 0% | 307 | 2,947 | +860% | 0 | 0 | — |
case-08 | fail→fail | 16,629 | 9,926 | -40% | 1 | 1 | 0% | 227 | 2,542 | +1020% | 0 | 0 | — |
case-09 | fail→fail | 10,396 | 12,921 | +24% | 1 | 1 | 0% | 293 | 2,990 | +920% | 0 | 0 | — |
case-10 | fail→fail | 15,733 | 11,288 | -28% | 1 | 1 | 0% | 211 | 2,673 | +1167% | 0 | 0 | — |
case-11 | fail→fail | 13,866 | 9,337 | -33% | 1 | 1 | 0% | 1,920 | 2,628 | +37% | 0 | 0 | — |
case-12 | fail→fail | 15,752 | 5,702 | -64% | 1 | 1 | 0% | 2,107 | 2,588 | +23% | 0 | 0 | — |
case-13 | fail→fail | 7,263 | 17,507 | +141% | 1 | 1 | 0% | 1,092 | 2,320 | +112% | 0 | 0 | — |
case-14 | fail→pass | 6,347 | 10,585 | +67% | 1 | 1 | 0% | 1,065 | 2,751 | +158% | 0 | 0 | — |
case-15 | pass→fail | 13,328 | 3,868 | -71% | 1 | 1 | 0% | 1,469 | 2,528 | +72% | 0 | 0 | — |
case-16 | pass→pass | 14,005 | 3,595 | -74% | 1 | 1 | 0% | 1,354 | 2,529 | +87% | 0 | 0 | — |
case-17 | fail→pass | 17,338 | 9,078 | -48% | 1 | 1 | 0% | 2,128 | 2,563 | +20% | 0 | 0 | — |
case-18 | pass→fail | 12,003 | 3,899 | -68% | 1 | 1 | 0% | 1,088 | 2,531 | +133% | 0 | 0 | — |
case-19 | fail→pass | 6,911 | 5,260 | -24% | 1 | 1 | 0% | 1,000 | 2,672 | +167% | 0 | 0 | — |
case-20 | fail→fail | 9,650 | 9,744 | +1% | 1 | 1 | 0% | 191 | 2,584 | +1253% | 0 | 0 | — |
case-21 | pass→fail | 12,277 | 9,313 | -24% | 1 | 1 | 0% | 1,923 | 2,502 | +30% | 0 | 0 | — |
case-22 | fail→pass | 13,687 | 11,943 | -13% | 1 | 1 | 0% | 2,187 | 3,204 | +47% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 13 counted toward the lift figure. The other 9 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +9 percentage points is the difference between those two pass rates over the 13 comparable cases. 4 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.