Skip to content

fix(workflow): trigger-issue drafts with an inner code fence escape the #391 link check — fenced_blocks() splits the draft at the inner fence #393

Closed

Description

@dezren39

Finding

PR #391 (commit 0a843b644f2d088deba5885dd21950733c64d3bb, merged as 6c027ad1) extended scripts/research_workflow.py so links inside fenced trigger-issue drafts are checked. The new parser still misses a realistic draft shape: a draft that contains its own inner fenced code block.

fenced_blocks() (scripts/research_workflow.py:428) closes the outer ```markdown draft at the first inner fence line, and issue_drafts() (scripts/research_workflow.py:445) only treats a fragment as a draft when that same fragment contains the workflow:issue marker. The marker is a trailing comment (per .agents/skills/issue-handoff/SKILL.md: "the trailing machine comment"), so in a draft shaped like:

```markdown
# Draft
- Concept Document: [concept](missing/nope.md)
```python
print(1)
```
<!-- workflow:issue {...} -->
```

the parse produces two fragments — ['# Draft\n- [concept](missing/nope.md)', '<!-- workflow:issue {...} -->'] — neither of which is both "a draft" and "carrying the pointer". The pointer fragment has no marker; the marker fragment has no links. links() (scripts/research_workflow.py:469) therefore never checks the pointer.

A related case in the same function: an unclosed draft fence is dropped entirely (fenced_blocks() only appends a block when it sees the closing fence), so that draft also escapes the check silently.

Evidence (verified against current main, 6c027ad1)

End-to-end through links() on a temp package, with the same broken pointer missing/nope.md in all three shapes:

Direct parser output for the nested shape: fenced_blocks() → ['# Draft\n- [bad](missing/nope.md)', '<!-- workflow:issue {} -->'], issue_drafts() → [''] (only the comment-stripped marker fragment).

This is exactly the failure class #382 / PR #391 set out to eliminate — a dead Context Pointer in a trigger-issue draft that research_workflow.py check reports as ok — just triggered by draft content (an embedded code block) rather than by the fence itself. Drafts routinely embed code/examples, so this is not an exotic shape.

Single-repo: scripts/research_workflow.py exists only in developing-today/code (confirmed in PR #391's body and by checking the other three repos).

Why it matters

The checker's guarantee after #391 reads as "trigger-issue draft links are validated". Any future draft that includes a code fence before its trailing marker silently loses that guarantee, and the first symptom is a dead pointer discovered by a human after the issue is created — the outcome #382 was filed to prevent.

Acceptance criteria

  • A regression test in scripts/tests/test_research_workflow.py: a fenced draft whose broken pointer appears before an inner fenced code block (marker trailing, after the inner block) fails check; the same draft with valid pointers passes.
  • A regression test: a draft in an unclosed fence does not silently pass — it is either checked or reported as a malformed/unclosed fence.
  • The fix does not weaken the existing exemption for non-draft fenced blocks (raw transcript evidence/code stay unchecked, as unfenced() documents), and template placeholders ({{…}}) remain skipped.
  • Full workflow suite still passes: python3 -m unittest discover -s scripts/tests -p 'test_*workflow*.py'.

Activity

  1. added a commit that references this issue on Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions