-
Notifications
You must be signed in to change notification settings - Fork 1.2k
fix(ce-compound): quote YAML array items starting with reserved indicators #607
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
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
162 changes: 162 additions & 0 deletions
162
docs/plans/2026-04-20-001-fix-ce-compound-yaml-safety-plan.md
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| --- | ||
| title: "fix(ce-compound): quote YAML array items starting with reserved indicators" | ||
| type: fix | ||
| status: active | ||
| date: 2026-04-20 | ||
| --- | ||
|
|
||
| # fix(ce-compound): quote YAML array items starting with reserved indicators | ||
|
|
||
| ## Overview | ||
|
|
||
| `/ce-compound` emits invalid YAML frontmatter when an array item in any | ||
| frontmatter array-of-strings field (primarily `symptoms:`, `applies_when:`, | ||
| `tags:`, `related_components:`) starts with a backtick (`` ` ``) or other YAML | ||
| 1.2 reserved indicator. Strict parsers (`yq`, `js-yaml` strict, PyYAML) reject | ||
| the resulting file. The existing angle-bracket-token guardrail (issue #602, | ||
| fixed in #603) does not generalize to array-item scalars. Teach the | ||
| `ce-compound` and `ce-compound-refresh` skills to quote unsafe array items, and | ||
| add a regression test so future prompt edits do not silently drop the rule. | ||
|
|
||
| ## Problem Frame | ||
|
|
||
| YAML 1.2 reserves `` ` `` as an indicator character at the start of a scalar. When | ||
| the frontmatter-writing subagent (or the Lightweight-mode orchestrator) writes | ||
| markdown-style backtick-wrapped shell commands as array items, the output is | ||
| visually correct markdown but syntactically invalid YAML. Strict parsers reject | ||
| the file; `ce-learnings-researcher`'s grep-first retrieval still matches on | ||
| substrings, which masks the problem — users silently accumulate unparseable | ||
| files. Issue #606 provides the reproduction, impact, and suggested fix. | ||
|
|
||
| ## Requirements Trace | ||
|
|
||
| - R1. New `ce-compound` output (Full and Lightweight modes) produces frontmatter | ||
| that parses under strict YAML 1.2 even when array items begin with reserved | ||
| indicator characters. | ||
| - R2. `ce-compound-refresh` Replace-flow subagent output meets the same bar. | ||
| - R3. The YAML-safety rule is captured as a durable contract in the authoritative | ||
| schema files (not only in prompt prose). | ||
| - R4. A regression test fails if the rule is removed from the prompts or the | ||
| schema contract, preventing silent drift. | ||
| - R5. Existing broken files already under `docs/solutions/` are out of scope. | ||
|
|
||
| ## Scope Boundaries | ||
|
|
||
| - Do not auto-repair existing invalid frontmatter in users' repos. | ||
| - Do not add a runtime YAML validator step to `ce-compound`. | ||
| - Do not change frontmatter schema fields, enum values, or track rules. | ||
| - Do not extend quoting guidance to `description:` or other scalar fields | ||
| beyond what #603 already covered. | ||
|
|
||
| ### Deferred to Separate Tasks | ||
|
|
||
| - A one-shot cleanup utility for repairing existing broken files in | ||
| `docs/solutions/`. | ||
| - Broader YAML-safety audit of other skills that write frontmatter. | ||
|
|
||
| ## Context & Research | ||
|
|
||
| ### Relevant Code and Patterns | ||
|
|
||
| - `plugins/compound-engineering/skills/ce-compound/SKILL.md` — Phase 2 step 5 | ||
| validates frontmatter; Lightweight mode step 3 writes in a single pass. | ||
| - `plugins/compound-engineering/skills/ce-compound/references/schema.yaml` — | ||
| authoritative frontmatter contract with `validation_rules` list. | ||
| - `plugins/compound-engineering/skills/ce-compound/references/yaml-schema.md` — | ||
| human-readable quick reference. | ||
| - `plugins/compound-engineering/skills/ce-compound/assets/resolution-template.md` — | ||
| concrete frontmatter examples for both tracks. | ||
| - `plugins/compound-engineering/skills/ce-compound-refresh/SKILL.md` — Replace | ||
| flow dispatches a subagent with the three support files as the source of | ||
| truth. | ||
| - `tests/compound-support-files.test.ts` — enforces byte-identical copies of | ||
| the three support files across the two skills. **Edits must be applied to | ||
| both skill copies.** | ||
| - `tests/frontmatter.test.ts` — validates strict YAML parseability of plugin | ||
| `SKILL.md` frontmatter. | ||
|
|
||
| ### Institutional Learnings | ||
|
|
||
| - Issue #602 / PR #603 fixed an analogous bug in `description:` with (a) a | ||
| sentence in the skill prompt and (b) a regression test. Apply the same shape. | ||
| - Per plugin `AGENTS.md` Rationale Discipline: rule body lives in on-demand | ||
| reference files, not `SKILL.md`. | ||
|
|
||
| ## Key Technical Decisions | ||
|
|
||
| - **Authoritative rule lives in `schema.yaml` `validation_rules` and a new | ||
| `yaml-schema.md` "YAML Safety Rules" section.** Subagents read these at write | ||
| time. | ||
| - **SKILL.md files get one-line pointers** at the frontmatter-writing spots. | ||
| - **Template files get a preamble comment** above each frontmatter block so | ||
| pattern-matching subagents see it. | ||
| - **Regression test asserts prompt-surface presence** (not runtime output | ||
| validity), mirroring the #603 pattern. | ||
| - **Mirror discipline:** all three support files are byte-identical across | ||
| the two skills. | ||
|
|
||
| ## Open Questions | ||
|
|
||
| ### Resolved During Planning | ||
|
|
||
| - *Where does the rule live?* → Support files (contract surface). | ||
| - *Which reserved characters?* → `` ` ``, `[`, `*`, `&`, `!`, `|`, `>`, `%`, | ||
| `@`, `?` plus the `": "` substring trap. | ||
| - *Test strategy?* → Prompt presence, not runtime output. | ||
| - *Field scope?* → Field-agnostic ("any array-of-strings frontmatter field"). | ||
|
|
||
| ## Implementation Units | ||
|
|
||
| - [ ] **Unit 1: Add YAML-safety rule to `schema.yaml` and `yaml-schema.md`** | ||
|
|
||
| **Files:** | ||
| - Modify: `plugins/compound-engineering/skills/ce-compound/references/schema.yaml` | ||
| - Modify: `plugins/compound-engineering/skills/ce-compound/references/yaml-schema.md` | ||
| - Modify: `plugins/compound-engineering/skills/ce-compound-refresh/references/schema.yaml` | ||
| - Modify: `plugins/compound-engineering/skills/ce-compound-refresh/references/yaml-schema.md` | ||
|
|
||
| **Approach:** Append one entry to `schema.yaml` `validation_rules`. Add a new | ||
| "## YAML Safety Rules" section to `yaml-schema.md` with indicator-character | ||
| list, `": "` trap, and before/after example. Mirror to both skills. | ||
|
|
||
| **Verification:** `bun test tests/compound-support-files.test.ts tests/frontmatter.test.ts` passes. | ||
|
|
||
| - [ ] **Unit 2: Add frontmatter-writing pointers to `ce-compound/SKILL.md`** | ||
|
|
||
| **Files:** `plugins/compound-engineering/skills/ce-compound/SKILL.md` | ||
|
|
||
| **Approach:** Add one-line pointer to `references/yaml-schema.md > YAML Safety | ||
| Rules` in Phase 2 step 5 and Lightweight mode step 3. | ||
|
|
||
| - [ ] **Unit 3: Add pointer to `ce-compound-refresh/SKILL.md` + template preambles** | ||
|
|
||
| **Files:** | ||
| - Modify: `plugins/compound-engineering/skills/ce-compound-refresh/SKILL.md` | ||
| - Modify: `plugins/compound-engineering/skills/ce-compound/assets/resolution-template.md` | ||
| - Modify: `plugins/compound-engineering/skills/ce-compound-refresh/assets/resolution-template.md` | ||
|
|
||
| **Approach:** Add one-line reminder to Replace-flow subagent dispatch. Add | ||
| HTML comment preamble above each frontmatter block in both template copies. | ||
|
|
||
| - [ ] **Unit 4: Add regression test for YAML-safety rule presence** | ||
|
|
||
| **Files:** `tests/compound-support-files.test.ts` (extend) | ||
|
|
||
| **Approach:** Add `describe("ce-compound YAML safety rule presence", ...)` | ||
| block asserting: `validation_rules` contains YAML-safety entry, `yaml-schema.md` | ||
| has "YAML Safety Rules" heading, `resolution-template.md` references the rule, | ||
| both `SKILL.md` files point to the rule. | ||
|
|
||
| ## Risks & Dependencies | ||
|
|
||
| | Risk | Mitigation | | ||
| |------|------------| | ||
| | LLM ignores the rule. | Three complementary surfaces (schema, yaml-schema, template preamble). | | ||
| | Future edits drop the rule. | Regression test (Unit 4). | | ||
| | Mirror drift. | Existing `compound-support-files.test.ts` enforces byte-identity. | | ||
|
|
||
| ## Sources & References | ||
|
|
||
| - Issue: EveryInc/compound-engineering-plugin#606 | ||
| - Prior art: PR #603 (`fix(ce-release-notes): backtick-wrap <skill-name> token`) | ||
| - Related tests: `tests/frontmatter.test.ts`, `tests/compound-support-files.test.ts` |
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
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
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
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
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
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
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
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
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
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test claims to protect both frontmatter-writing locations, but
mentions.length >= 2counts allyaml-schema.mdoccurrences in the file, including unrelated references. Becausece-compound/SKILL.mdalready contains a non-write-path mention, one of the two targeted write-path pointers can be removed and the test will still pass. That leaves either Full mode or Lightweight mode unprotected against regressing the YAML-quoting guidance.Useful? React with 👍 / 👎.