fix: reject duplicated top-level workflow output sections - #2
Open
eisen0419 wants to merge 1 commit into
Open
Conversation
Repeated <control>/<analysis>/<refs> blocks could evade the documented exactly-one layout rule: collectSections records at most one match per section and sanitized recovery could drop a repeated trailing block before re-parsing. Count canonical opening tags outside every matched section span during layout validation and emit the existing duplicate_section issue when a tag repeats, routing the output into the invalid-output retry path. Literal tags inside section content (e.g. protocol text quoted in control JSON strings) remain tolerated.
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.
Problem
docs/usage.mdstates that artifact-graph task output is parsed strictly as exactly one<control>, followed by one<analysis>, followed by one<refs>, with no outside prose. In@agwab/pi-workflow@0.9.0, repeated section tags can evade that contract:collectSectionsrecords at most one match for each expected section, sovalidateSectionCountsnever observes a count above one, and the sanitized-output fallback can discard a repeated trailing section before re-parsing.A qualification run demonstrated the effect: an output with two complete
<control>blocks was accepted withoutputValidation.valid=true, no output retries, and a completed run (workflow_mrwrw4lv_5f2c2d). By comparison, an invalid control JSON type followed the normal invalid-output retry path and ended asworkflow_output_invalid_exhausted.Reproduction
Use an otherwise valid protocol response and append a second section:
Before this change,
parseWorkflowOutputForBundlesanitizes the first three sections and returns valid output.Fix
During layout validation, count canonical opening tags that appear outside every matched section span. When a tag is observed more than once, emit the existing
duplicate_sectionvalidation issue with the section name and observed count, which routes the output into the existing invalid-output retry/rejection path. Sanitized-output recovery is also stopped when any canonical tag is duplicated, so recovery cannot erase the evidence before validation.Counting only outside matched spans preserves the documented tolerance for literal tags inside section content: protocol text quoted inside control JSON strings (covered by the existing test "workflow output parser tolerates literal closing tags inside JSON strings") is still accepted, because those occurrences sit inside the matched
<control>span.Tests
test/unit/output-duplicate-section-rejection.test.mjsadds regression coverage:<control>block →duplicate_section, output invalid (bothparseWorkflowOutputandparseWorkflowOutputForBundle);<analysis>block →duplicate_section;<refs>block → still rejected (absorbed into the refs span and fails refs JSON validation);npm run validatepasses (713/713 unit tests, typecheck, script and public-surface checks).Compatibility
Valid outputs containing exactly one required section of each kind are unchanged. Outputs that repeat
<control>,<analysis>, or<refs>at the top level now correctly enter the existing invalid-output retry/rejection path, matching the documented strict protocol.