fix(controlplane): compare contracts semantically for change detection#3233
fix(controlplane): compare contracts semantically for change detection#3233javirln wants to merge 1 commit into
Conversation
Contract change-detection compared raw bytes, so re-applying the same contract through different client paths (verbatim `wf contract apply` vs the batch `apply` splitter, which re-marshals YAML) produced spurious revisions and false dry-run drift. The comparison now parses both the stored and incoming bodies and compares their canonical proto form, making it insensitive to serialization/formatting differences while still detecting genuine content changes. Stored raw bodies are unchanged and still served back verbatim. Assisted-by: Claude Code Signed-off-by: Javier Rodriguez <javier@chainloop.dev> Chainloop-Trace-Sessions: 606de1a5-e4ab-480b-8009-722416f5e18d
AI Session Analysis
|
| Status | Attribution | File | Lines |
|---|---|---|---|
| modified | ai | app/controlplane/pkg/biz/workflowcontract_test.go |
+122 / -1 |
| modified | ai | app/controlplane/pkg/biz/workflowcontract.go |
+46 / -2 |
| modified | ai | app/controlplane/pkg/biz/workflowcontract_integration_test.go |
+23 / -0 |
| modified | ai | app/controlplane/pkg/data/workflowcontract.go |
+5 / -3 |
Policies (4)
| Status | Policy | Material | Messages |
|---|---|---|---|
| ✅ Passed | ai-config-ai-agents-allowed |
ai-coding-session-606de1 |
- |
| ✅ Passed | ai-config-no-dangerous-commands |
ai-coding-session-606de1 |
- |
| ✅ Passed | ai-config-no-secrets |
ai-coding-session-606de1 |
- |
| ✅ Passed | ai-config-mcp-servers-allowed |
ai-coding-session-606de1 |
- |
Powered by Chainloop and Chainloop Trace
migmartri
left a comment
There was a problem hiding this comment.
I don't know, this looks strange, shouldn't we take a look at why different clients produce different outputs? at the end, we have the raw content.
Also, does this mean that if I add a comment now in the yaml it will not be saved because the marshalled output is the same?
Description
Contract change-detection compared raw bytes, so re-applying the same contract through different client paths produced spurious revisions and false drift on dry-run apply. The verbatim
wf contract applypath sends the on-disk bytes, while the batchapplypath (including--dry-run) re-marshals the YAML, re-indenting it. Because the stored bytes never matched the reindented incoming bytes, every drift check reported the contract as changed.The server comparison is now semantic instead of raw-byte. A new
biz.ContractRawEqualhelper parses both the stored and incoming bodies (reusing the existing unmarshal/validate path) and compares their canonical proto form, so formatting-only differences (indentation, key order, YAML vs JSON) no longer register as changes. Both the real-apply revision decision andRevisionWouldChangeuse it. Stored raw bodies are unchanged and still served back to clients verbatim; only the equality check changes.Re-applying the same contract via any path now reports "unchanged", a genuine content edit is still detected as a change, and applying the same contract twice remains idempotent.
Closes PFM-6465
AI disclosure
Claude Code assisted in producing this change.