-
Notifications
You must be signed in to change notification settings - Fork 0
fix(core): Phase-1 validation must accept sourcePatch rule updates (#566) #596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
4607e49
9fa6cdc
300ad03
14fd09b
9079bad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@linchkit/core": patch | ||
| --- | ||
|
|
||
| Fix Phase-1 proposal validation rejecting `sourcePatch`-carrying rule updates as `MISSING_DEFINITION` (#566). A "say→change an existing code-condition rule's threshold" proposal carries a definition-less change whose `sourcePatch` IS the specification (value-validated at assembly, re-validated by the patcher at graduation). Phase 1 now skips the definition requirement for such a change — like `revert`/`delete` — so the governed draft can reach the approval gate and graduate. Without this, every natural-language rule-threshold update failed Phase 1 and was unapprovable (the resolver produced a correct proposal that could never be approved). Caught by live testing of the chat-assistant approval flow. |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -194,6 +194,38 @@ export function validatePhase1(options: { | |||||
| // the target-specific definition validation below) just as we skip deletes, | ||||||
| // so a governance-safe draft rollback Proposal can reach the approval gate. | ||||||
| if (change.target === "revert") continue; | ||||||
| // A change carrying a `sourcePatch` (#566 "say→change an existing | ||||||
| // code-condition rule's threshold") intentionally has NO `definition`: it | ||||||
| // rewrites a single named constant in existing source, so the sourcePatch IS | ||||||
| // the specification (value-validated at assembly via `isSafeValueLiteral`, | ||||||
| // and the patcher re-validates at graduation). Skip the MISSING_DEFINITION | ||||||
| // requirement — like revert/delete — so the governed draft can reach the | ||||||
| // approval gate and graduate. Without this, every NL rule-threshold update | ||||||
| // fails Phase 1 and is unapprovable. Still validate the patch's OWN shape | ||||||
| // here so a malformed sourcePatch is caught early at Phase 1 rather than | ||||||
| // failing opaquely during graduation. | ||||||
| // Scope the carve-out to exactly the production case it exists for — a | ||||||
|
laofahai marked this conversation as resolved.
|
||||||
| // `rule` `update` (the NL threshold change). `sourcePatch` is an optional | ||||||
| // field on the BASE ProposalChange, so a crafted `entity`/`action` change | ||||||
| // carrying a sourcePatch must NOT get the definition-less pass; it falls | ||||||
| // through to MISSING_DEFINITION like any other definition-less change. | ||||||
| if (change.sourcePatch && change.target === "rule" && change.operation === "update") { | ||||||
| const { filePath, constantName, newValueLiteral } = change.sourcePatch; | ||||||
| if (!filePath || !constantName || !newValueLiteral) { | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: whitespace-only field values bypass the
Suggested change
The same |
||||||
| errors.push({ | ||||||
| code: "INVALID_SOURCE_PATCH", | ||||||
| message: `Change for "${change.name}" has an invalid or incomplete sourcePatch specification`, | ||||||
| target: change.name, | ||||||
| }); | ||||||
| } | ||||||
| // A definition-LESS sourcePatch change is self-specifying: skip the | ||||||
| // MISSING_DEFINITION requirement AND the target-specific definition | ||||||
| // validation below. But if a `definition` is ALSO present (permitted by | ||||||
| // the ProposalChange type, though not produced today), fall through so | ||||||
| // validateRule()/validateEntity()/… still runs and catches the | ||||||
| // inconsistency rather than silently accepting a malformed definition. | ||||||
| if (!change.definition) continue; | ||||||
| } | ||||||
| if (!change.definition) { | ||||||
| errors.push({ | ||||||
| code: "MISSING_DEFINITION", | ||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.