Repository navigation
Description
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:
- Control — no inner fence: raises
missing link target: missing/nope.md✅ (the fix(workflow): check links inside fenced trigger-issue drafts (#382) #391 fix works here) - Inner
```pythonblock between the pointer and the trailing marker: no error ❌ - Unclosed draft fence: no error ❌
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) failscheck; 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
Merge pull request #400 from developing-today/sweep/393-nested-fence-…