Repository navigation
fix(plv): recognize structural mandate label variants - #55
Merged
Merged
Conversation
Recognize Mandate, User mandate, Principal instruction, and bare Principal mandate headers when they are real section headers, so an omitted model quote is not floored to 0.25. Labels inside quotes, tool output, or the proposed action do not count. Disagreeing sections fail closed, and a fabricated model quote is never replaced by a fallback span. Co-authored-by: Raul Jäger <raul@thoughtproof.ai>
Match fenced blocks by character and length, hold the verdict when mandate sections conflict, ignore legacy labels after the action boundary, and accept Principal mandate (verbatim): as a header. Co-authored-by: Raul Jäger <raul@thoughtproof.ai>
CommonMark allows only ASCII spaces and tabs after a closing fence marker. String.trim() also strips NBSP and other Unicode whitespace, which closed the block early and recovered the text inside it. Co-authored-by: Raul Jäger <raul@thoughtproof.ai>
One recognizer both cuts a mandate span and closes the mandate region, including inline labels, and only ASCII space or tab is structural whitespace. Other whitespace before a section label recovers nothing. Mandate identity keeps internal characters, so a different space is a conflict and holds the verdict. Co-authored-by: Raul Jäger <raul@thoughtproof.ai>
Co-authored-by: Raul Jäger <raul@thoughtproof.ai>
ThoughtProof
marked this pull request as ready for review
October 30, 2026 07:28
Merged
5 tasks done
ThoughtProof
added a commit
that referenced
this pull request
Oct 30, 2026
Bump version to 0.8.13 and add CHANGELOG entry for #55.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Structural mandate labels are recovered only from the preamble. One recognizer both cuts the span and closes that region, on a separate line or inline. The separator is ASCII space, tab, or a newline. NBSP, VT, FF, BOM, and EM SPACE before a section label recover no mandate, so an injected
USER INSTRUCTION:orMandate:after that point cannot become the quote.Mandate texts are compared literally after the existing outer trim. Internal spaces, NBSP, BOM, and tabs are not collapsed, so two exclusive file targets are
MANDATE_CONFLICTand the verdict is HOLD. An existing BLOCK is not loosened. A model quote is still kept and provenance-checked.Fences still close only on the same character, with a run at least as long as the opener, and only ASCII spaces or tabs after that run. Package version stays
0.8.12. Sentinel is not changed. This PR stays a draft.Owner patch on
18cd289Ambiguous preamble boundaries now return a blocking conflict with no quote, so a real model quote cannot turn that case into ALLOW. The boundary scan stops at the first action or tool section, so labels in that content cannot erase a conflict already found. A trailing ASCII space or tab does not hide a non-structural separator before that run (NBSP plus space, or NBSP plus tab, stays ambiguous). A genuinely absent mandate stays absent.
Tests
The original 20 cases in
src/plan/test-mandate-owner-review.tsare unchanged.The owner's 17 boundary and literal-target cases are in
src/plan/test-mandate-unicode-boundaries.ts. Assertions matchunicode-boundaries-and-literals.test.mjs. The harness callsevaluateItemwith a local model fixture;tier1includesbackend: 'llm'becauseTier1Configrequires it.Extra negatives in that file cover VT, FF, NBSP, BOM, and EM SPACE before
Proposed action:,Agent reasoning:,Tool output:, andWALLET BALANCE:, the same separators inline beforeProposed action:, an injectedMandate:as well asUSER INSTRUCTION:, and tab-versus-space filenames in both the conflicting and identical cases.src/plan/test-mandate-boundary-scope.tslocks the owner patch: conflict scope, mixed separators, and the absent-versus-ambiguous distinction. Review harness files were run locally and were not committed.Results on
18cd289git apply --checkthengit applyof the owner patch: cleannpm ci: passnpm run build: passnpm run test:plan: 450 passed, 0 failednode --testontests/ask-verify-mode.test.mjs,tests/custom-provider.test.mjs,tests/rv-pipeline.test.mjs: 43 passed, 0 failednpm run test:package: 2 passed, 0 failednpm run check:boundaries: passreview-tests/*.test.mjs: 45 passed, 0 failedSentinel
Still pinned to
pot-cli@0.8.12. A pin bump waits on a published release. Not done here.