Skip to content

Add explicit end marker syntax for inline skills and sub-agents - #51446

Merged
pelikhan merged 23 commits into
mainfrom
copilot/update-parser-end-marker
Aug 9, 2026
Merged

Add explicit end marker syntax for inline skills and sub-agents#51446
pelikhan merged 23 commits into
mainfrom
copilot/update-parser-end-marker

Conversation

Copilot AI commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Inline skills (## skill: \name`) and inline sub-agents (## agent: `name`) close their block implicitly at the next ##` heading or EOF, with no way to close explicitly. This breaks down when a block is embedded mid-document — e.g. via an import — silently swallowing whatever follows the import point.

Explicit end marker

  • New optional syntax: ## end skill: \name`/## end agent: `name`` — a normal ATX H2 heading, markdownlint-friendly (unique heading text avoids MD024) and symmetric with the start marker.
  • When present, extraction uses it as the exact boundary regardless of any ## headings inside the block, and content after it is preserved rather than discarded.
  • An end marker with no matching start (typo, wrong order) is a hard parse error.
  • Fully backward compatible: files without end markers behave exactly as before.
## skill: `reporting`
---
description: Report formatting guidelines
---
- Use `###` (or lower) headers only.
## end skill: `reporting`

This content is no longer swallowed by the skill block.

Parser changes

  • pkg/parser/inline_section_helpers.go, inline_skill_extractor.go, sub_agent_extractor.go: cursor-based extraction with end-marker matching and orphan-marker detection.
  • actions/setup/js/extract_inline_skills.cjs, extract_inline_sub_agents.cjs: mirrors the Go logic for the runtime extraction path.
  • Comprehensive test coverage added on both sides.

Runtime-import safety net

{{#runtime-import ...}} content is spliced into the assembled prompt before skill/agent extraction runs, so an imported snippet with no explicit end marker could still swallow whatever gets spliced in after it. runtime_import.cjs now automatically makes any unterminated skill/agent block in each import's own content explicit — inserting the end marker at the same boundary implicit closing would already use — before splicing it in. This makes every runtime import import-safe by default without requiring authors to opt in.

Docs

  • New ADR (docs/adr/51500-...md) documenting the design and rejected alternatives (HTML comments, ---/fenced blocks, bare ## end).
  • Updated inline-sub-agents.md, cost-management.md, glossary.md.

Demonstration

.github/workflows/shared/reporting.md (imported by ~90 workflows) now exposes its guidelines as an inline ## skill: \reporting`` block bounded by the explicit end marker, exercising the feature and the runtime-import safety net against a real, high-fan-out shared snippet.


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 11.9 AIC · ⌖ 6.64 AIC · ⊞ 8.5K ·
Comment /souschef to run again


Run: https://github.com/github/gh-aw/actions/runs/31279642957> Generated by 👨‍🍳 PR Sous Chef · gpt54 · 13 AIC · ⌖ 5.43 AIC · ⊞ 8.5K ·

Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 10.4 AIC · ⌖ 6.29 AIC · ⊞ 8.5K ·
Comment /souschef to run again


Run: https://github.com/github/gh-aw/actions/runs/31287357931> Generated by 👨‍🍳 PR Sous Chef · gpt54 · 20.7 AIC · ⌖ 6.68 AIC · ⊞ 8.5K ·

Comment /souschef to run again


run: https://github.com/github/gh-aw/actions/runs/31293411688> Generated by 👨‍🍳 PR Sous Chef · gpt54 · 3.76 AIC · ⌖ 6.55 AIC · ⊞ 8.5K ·

Comment /souschef to run again

Copilot AI and others added 3 commits August 8, 2026 18:29
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI requested a review from pelikhan August 8, 2026 18:58
@pelikhan
pelikhan marked this pull request as ready for review August 8, 2026 19:07
Copilot AI balanced review requested due to automatic review settings August 8, 2026 19:07
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • api.individual.githubcopilot.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "api.individual.githubcopilot.com"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds explicit end markers for inline skills and sub-agents, preserving surrounding prompt content and protecting runtime imports.

Changes:

  • Implements matching end-marker extraction in Go and JavaScript.
  • Automatically terminates imported inline blocks and expands test coverage.
  • Documents the syntax, updates shared reporting guidance, and recompiles affected workflows.
Show a summary per file
File Description
pkg/parser/inline_section_helpers.go Adds shared end-marker extraction logic.
pkg/parser/inline_skill_extractor.go Supports explicit skill endings.
pkg/parser/sub_agent_extractor.go Supports explicit agent endings.
pkg/parser/inline_skill_extractor_test.go Tests Go skill extraction.
pkg/parser/sub_agent_extractor_test.go Tests Go agent extraction.
actions/setup/js/extract_inline_skills.cjs Implements runtime skill extraction.
actions/setup/js/extract_inline_sub_agents.cjs Implements runtime agent extraction.
actions/setup/js/extract_inline_skills.test.cjs Tests JavaScript skill extraction.
actions/setup/js/extract_inline_sub_agents.test.cjs Tests JavaScript agent extraction.
actions/setup/js/runtime_import.cjs Terminates blocks within imports.
actions/setup/js/runtime_import.test.cjs Tests import safety behavior.
docs/adr/51500-explicit-end-marker-for-inline-skills-and-sub-agents.md Records the syntax decision.
docs/src/content/docs/reference/inline-sub-agents.md Documents agent end markers.
docs/src/content/docs/reference/cost-management.md Documents bounded inline skills.
docs/src/content/docs/reference/glossary.md Updates inline-agent terminology.
.github/workflows/shared/reporting.md Converts reporting guidance into a bounded skill.
.github/workflows/workflow-normalizer.lock.yml Refreshes generated metadata.
.github/workflows/workflow-health-manager.lock.yml Refreshes generated metadata.
.github/workflows/workflow-generator.lock.yml Refreshes generated metadata.
.github/workflows/visual-regression-checker.lock.yml Refreshes generated metadata.
.github/workflows/update-astro.lock.yml Refreshes generated metadata.
.github/workflows/tidy.lock.yml Refreshes generated metadata.
.github/workflows/technical-doc-writer.lock.yml Refreshes generated metadata.
.github/workflows/super-linter.lock.yml Refreshes generated metadata.
.github/workflows/sub-issue-closer.lock.yml Refreshes generated metadata.
.github/workflows/squad-plan.lock.yml Refreshes generated metadata.
.github/workflows/squad-game-planner.lock.yml Refreshes generated metadata.
.github/workflows/sighthound-security-scan.lock.yml Refreshes generated metadata.
.github/workflows/security-compliance.lock.yml Refreshes generated metadata.
.github/workflows/schema-feature-coverage.lock.yml Refreshes generated metadata.
.github/workflows/research.lock.yml Refreshes generated metadata.
.github/workflows/repo-tree-map.lock.yml Refreshes generated metadata.
.github/workflows/refiner.lock.yml Refreshes generated metadata.
.github/workflows/pr-nitpick-reviewer.lock.yml Refreshes generated metadata.
.github/workflows/pr-description-caveman.lock.yml Refreshes generated metadata.
.github/workflows/poem-bot.lock.yml Refreshes generated metadata.
.github/workflows/pdf-summary.lock.yml Refreshes generated metadata.
.github/workflows/necromancer.lock.yml Refreshes generated metadata.
.github/workflows/lint-monster.lock.yml Refreshes generated metadata.
.github/workflows/jsweep.lock.yml Refreshes generated metadata.
.github/workflows/issue-triage-agent.lock.yml Refreshes generated metadata.
.github/workflows/issue-arborist.lock.yml Refreshes generated metadata.
.github/workflows/gpclean.lock.yml Refreshes generated metadata.
.github/workflows/go-pattern-detector.lock.yml Refreshes generated metadata.
.github/workflows/functional-pragmatist.lock.yml Refreshes generated metadata.
.github/workflows/firewall-escape.lock.yml Refreshes generated metadata.
.github/workflows/example-failure-category-filter.lock.yml Refreshes generated metadata.
.github/workflows/evoskill-evolver.lock.yml Refreshes generated metadata.
.github/workflows/eslint-monster.lock.yml Refreshes generated metadata.
.github/workflows/eslint-miner.lock.yml Refreshes generated metadata.
.github/workflows/dictation-prompt.lock.yml Refreshes generated metadata.
.github/workflows/dev.lock.yml Refreshes generated metadata.
.github/workflows/deployment-incident-monitor.lock.yml Refreshes generated metadata.
.github/workflows/dependabot-go-checker.lock.yml Refreshes generated metadata.
.github/workflows/deepsec-security-scan.lock.yml Refreshes generated metadata.
.github/workflows/daily-syntax-error-quality.lock.yml Refreshes generated metadata.
.github/workflows/daily-spec-coverage-kiro.lock.yml Refreshes generated metadata.
.github/workflows/daily-schema-audit-cursor.lock.yml Refreshes generated metadata.
.github/workflows/daily-regression-audit-kiro.lock.yml Refreshes generated metadata.
.github/workflows/daily-pr-review-cursor.lock.yml Refreshes generated metadata.
.github/workflows/daily-hippo-learn.lock.yml Refreshes generated metadata.
.github/workflows/daily-go-test-parallelizer.lock.yml Refreshes generated metadata.
.github/workflows/daily-aw-cross-repo-compile-check.lock.yml Refreshes generated metadata.
.github/workflows/craft.lock.yml Refreshes generated metadata.
.github/workflows/copilot-pr-nlp-analysis.lock.yml Refreshes generated metadata.
.github/workflows/copilot-pr-merged-report.lock.yml Refreshes generated metadata.
.github/workflows/copilot-opt.lock.yml Refreshes generated metadata.
.github/workflows/copilot-centralization-optimizer.lock.yml Refreshes generated metadata.
.github/workflows/cli-version-checker.lock.yml Refreshes generated metadata.
.github/workflows/auto-triage-issues.lock.yml Refreshes generated metadata.
.github/workflows/artifacts-summary.lock.yml Refreshes generated metadata.
.github/workflows/approach-validator.lock.yml Refreshes generated metadata.

Review details

Tip

Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 103/103 changed files
  • Comments generated: 5
  • Review effort level: Balanced

// skill block: "## end skill: `name`". It mirrors the start marker's name
// rules. When present, it closes the skill block exactly at that heading
// instead of at the next H2 heading or EOF.
var inlineSkillEndRegex = regexp.MustCompile("(?m)^##[ \t]+end[ \t]+skill:[ \t]+`([a-z][a-z0-9_-]*)`[ \t]*$")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in e814c7c: ExtractInlineSkills now validates standalone end markers before the no-start return and reports them as errors.

Comment thread docs/src/content/docs/reference/inline-sub-agents.md Outdated
Comment thread pkg/parser/sub_agent_extractor.go Outdated
}

mainMarkdown, agents = extractInlineSections(markdown, allStarts, func(name, content string) InlineSubAgent {
mainMarkdown, agents, err = extractInlineSections(markdown, allStarts, subAgentEndRegex, func(name, content string) InlineSubAgent {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in e814c7c: ExtractInlineSubAgents now rejects standalone ## end agent markers before the no-start return.

Comment on lines +132 to +134
* Throws if an end marker's name does not correspond to any start marker of
* the same name found within its search window (an "orphan" end marker),
* which is almost always an authoring mistake such as a typo.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in e814c7c: the JS skill extractor now validates end markers before returning when no skill starts are present.

Comment on lines +74 to +76
* Throws if an end marker's name does not correspond to any start marker of
* the same name found within its search window (an "orphan" end marker),
* which is almost always an authoring mistake such as a typo.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in e814c7c: the JS sub-agent extractor now rejects standalone end-agent markers before returning no agents.

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

✅ Design Decision Gate — ADR Verified

ADR reviewed: ADR-51500: Explicit End Marker for Inline Skills and Sub-Agents — implementation aligns with the stated decision. Great work! 🏗️

📋 Verification Summary

The PR faithfully implements every commitment in ADR-51500:

  • End-marker syntax (✔): ## end skill: \name`and## end agent: `name`` are added as optional explicit closing markers, exactly as the ADR specifies. The name must match the corresponding start marker; mismatches produce a hard parse error as required.
  • Go parser (✔): pkg/parser/inline_section_helpers.go, inline_skill_extractor.go, and sub_agent_extractor.go implement cursor-based extraction with end-marker matching, as called out in the ADR's normative spec (Part 2, Extraction Ordering).
  • JS runtime extractors (✔): actions/setup/js/extract_inline_skills.cjs and extract_inline_sub_agents.cjs mirror the Go logic with identical marker syntax, name rules, and closing semantics, satisfying the ADR's MUST requirement for both layers.
  • Runtime-import safety net (✔): runtime_import.cjs automatically closes any unterminated skill/agent block in each import's own content before splicing, exactly the mechanism described in the Decision section.
  • Backward compatibility (✔): Files without end markers continue to close at the next ## heading or EOF, as the ADR requires.
  • Docs (✔): inline-sub-agents.md, cost-management.md, and glossary.md updated; ADR itself committed on the branch.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · sonnet46 · 38.7 AIC · ⌖ 23.3 AIC · ⊞ 8.7K ·
Comment /review to run again

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 92/100 — Excellent

Analyzed 18 test(s): 18 design, 0 implementation, 0 violation(s).

📊 Metrics (18 tests)
Metric Value
Analyzed 18 (Go: 0, JS: 18)
✅ Design 18 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 13 (72%)
Duplicate clusters 0
Inflation No
🚨 Violations 0
Test File Classification Issues
explicit end marker resumes main content extract_inline_skills.test.cjs design_test / behavioral_contract / high_value
explicit end marker allows nested H2 headings extract_inline_skills.test.cjs design_test / behavioral_contract / high_value
supports mixing explicit and implicit end boundaries extract_inline_skills.test.cjs design_test / behavioral_contract / high_value
throws on orphan end marker (no matching start) extract_inline_skills.test.cjs design_test / behavioral_contract / high_value
throws when end marker names different skill extract_inline_skills.test.cjs design_test / behavioral_contract / high_value
falls back to implicit H2 when end marker malformed extract_inline_skills.test.cjs design_test / behavioral_contract / high_value
explicit end marker resumes main content extract_inline_sub_agents.test.cjs design_test / behavioral_contract / high_value
explicit end marker allows nested H2 headings extract_inline_sub_agents.test.cjs design_test / behavioral_contract / high_value
supports mixing explicit and implicit end boundaries extract_inline_sub_agents.test.cjs design_test / behavioral_contract / high_value
throws on orphan end marker (no matching start) extract_inline_sub_agents.test.cjs design_test / behavioral_contract / high_value
throws when end marker names different agent extract_inline_sub_agents.test.cjs design_test / behavioral_contract / high_value
falls back to implicit H2 when end marker malformed extract_inline_sub_agents.test.cjs design_test / behavioral_contract / high_value
implicitly close unterminated skill block runtime_import.test.cjs design_test / behavioral_contract / high_value
implicitly close unterminated agent block runtime_import.test.cjs design_test / behavioral_contract / high_value
leave already-closed skill block unchanged runtime_import.test.cjs design_test / behavioral_contract / high_value
no end markers when no skill/agent markers present runtime_import.test.cjs design_test / behavioral_contract / high_value
unterminated skill block must not swallow next import runtime_import.test.cjs design_test / behavioral_contract / high_value
unterminated agent block must not swallow workflow body runtime_import.test.cjs design_test / behavioral_contract / high_value

Test inflation ratios (new lines):

  • extract_inline_skills.test.cjs / .cjs: 53 / 153 = 0.35 ✅
  • extract_inline_sub_agents.test.cjs / .cjs: 53 / 153 = 0.35 ✅
  • runtime_import.test.cjs / .cjs: 44 / 32 = 1.38 ✅

Verdict

Passed. 0% implementation tests (threshold: 30%). All 18 new tests verify user-visible behavioral contracts.

Highlights:

  • 🛡️ Security-relevant design invariants: The runtime_import tests explicitly verify that unterminated skill/agent blocks from one imported file cannot swallow content from subsequent imports or the main workflow body — this is exactly the class of correctness bug that would create hard-to-debug silent failures in production.
  • 🔁 Idempotency coverage: The "already-closed block unchanged" test guards against duplicate end-marker injection.
  • 🔴 Error-path coverage: Two throw tests per extractor verify that orphan and mismatched end markers produce actionable errors rather than silently misparse.
  • 📐 Boundary precision: Malformed end-marker fallback tests verify the parser does not accidentally accept lookalike syntax.

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 · 81.5 AIC · ⌖ 10 AIC · ⊞ 7.6K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 92/100. 0% implementation tests (threshold: 30%). All 18 new tests are high-value behavioral contracts covering the explicit end-marker feature.

@pelikhan

pelikhan commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

@copilot resolve the merge conflicts on this branch.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Add explicit end marker syntax for inline skills and sub-agents

This is a clean, well-scoped feature with thorough tests on both the Go and JS sides. The implementation is consistent across both extractors (skills and sub-agents) and between the two language layers.

What looks good

  • Symmetric syntax## end skill: \name`mirrors## skill: `name`` exactly; the same holds for agents. Unique heading text per block satisfies markdownlint MD024.
  • Backward compatibility — files without end markers behave identically to before.
  • Proactive import safetycloseUnterminatedInlineMarkers automatically closes unterminated blocks in runtime imports before splicing, protecting shared snippets even when authors omit the new syntax. Good default.
  • Orphan detection — mismatched end marker names are hard errors with the offending name in the message.
  • Window-bounded matching — end markers are only eligible to close the preceding same-named start marker; cross-marker closing is correctly rejected.
  • ADR-51500 — thorough decision record including alternatives and an RFC 2119 normative spec.
  • reporting.md conversion — real-world validation of the feature on the shared reporting snippet.

Minor observations (non-blocking)

  1. collapseBlankLines runs unconditionally in extractInlineSections — even when there are no explicit end markers, the reassembly now collapses 3+ consecutive blank lines in main markdown. This is a very minor behavior difference from the old strings.TrimRight(markdown[:firstStart], "\n") for documents with runs of blank lines before the first marker. Harmless in practice and reasonable normalization, but worth noting.

  2. prevExplicit=false tail is intentionally dropped — when the last skill in a document is implicit (no end marker), content after cursor is not appended to mainParts. This preserves the pre-ADR behavior: "everything after the last implicit skill is consumed by it." The test coverage confirms this is intentional.

No blocking issues. Approved.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 139.2 AIC · ⌖ 7.25 AIC · ⊞ 5.4K

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /tdd and /codebase-design — no blocking issues, but four targeted improvements worth addressing.

📋 Key Themes & Highlights

Key Themes

  • Test coverage gaps: The malformed-marker fallback test does not assert mainContent, leaving the silent-drop of trailing content undetected. The new runtime_import tests use a comma-expression pattern inherited from surrounding code — worth verifying they register as distinct test cases.
  • Duplicated traversal logic: closeUnterminatedSkillMarkers / closeUnterminatedSubAgentMarkers each re-implement the window/cursor/H2 scan already in extractInlineSkills / extractInlineSubAgents. Four copies to keep in sync.
  • Error messages lack position info: Orphan end-marker errors in both Go and JS tell you the wrong name but not the line number, slowing diagnosis in large files.
  • Composition order of closeUnterminatedInlineMarkers: The skill→agent application order is correct but untested; a single regression test would lock it in.

Positive Highlights

  • ✅ Excellent backward-compatibility story: files without end markers are completely unaffected.
  • ✅ Orphan end-marker detection (wrong name) is a hard error in both Go and JS — fail-fast at parse time rather than silently mis-extracting.
  • ✅ Runtime-import safety net (closeUnterminatedInlineMarkers) is a clever defence-in-depth layer; the design decision is well-documented in the new ADR.
  • ✅ Test coverage is comprehensive for the happy paths (nested H2s, mixed explicit/implicit, multi-skill, multi-agent).
  • ✅ Go and JS implementations are structurally symmetric, making cross-language reasoning easier.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 152.3 AIC · ⌖ 7.09 AIC · ⊞ 7.1K
Comment /matt to run again

expect(skills).toHaveLength(1);
expect(skills[0].name).toBe("reporting");
}
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The malformed-marker test does not assert what happens to Tail. — which is silently dropped.

The test only checks skills[0].name, not mainContent. With a malformed end marker the skill closes at the implicit H2 boundary (prevExplicit = false), so the text that follows (including Tail.) is never captured in mainParts. This silent-drop goes undetected and is a latent regression risk.

💡 Suggested addition

Add a mainContent assertion that makes the intended behaviour explicit:

// If silent-drop is intentional (legacy parity), assert it:
expect(mainContent).not.toContain("Tail.");
// Or, if the content should be preserved after the boundary, fix the implementation
// and assert: expect(mainContent).toContain("Tail.");

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in e814c7c: the malformed-marker test now asserts the legacy mainContent disposition for Tail. explicitly.

* @param {string} content - Markdown that may contain "## skill:" blocks.
* @returns {string} Content with implicit end markers made explicit.
*/
function closeUnterminatedSkillMarkers(content) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] closeUnterminatedSkillMarkers duplicates the marker-matching traversal logic already inside extractInlineSkills, creating two copies to keep in sync.

Both functions iterate startMatches, compute windowEnd, scan endMarkers, and find the implicit H2 boundary. When the end-marker logic changes, it must be updated in both places. The duplication mirrors itself in extract_inline_sub_agents.cjs as well, giving four copies total.

💡 Deepening opportunity

Consider extracting a shared _scanMarkerBoundaries(content, startRe, endRe) helper that returns { start, end, implicit }[] for each block. Both extractInlineSkills and closeUnterminatedSkillMarkers (and their agent counterparts) can be implemented on top of this helper without duplicating the window/cursor arithmetic.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in e814c7c: shared inline end-marker collection/error helpers now avoid duplicating that utility logic across skill and sub-agent extractors.


const orphan = endMarkers.find((_, ei) => !usedEnd[ei]);
if (orphan) {
throw new Error(`[extractInlineSkills] end marker for unknown skill "${orphan.name}" (no matching start marker with that name)`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The orphan end-marker error does not include the position (line/offset) where the orphan was found, making it hard to locate in large files.

The Go equivalent (inline_section_helpers.go:148) has the same gap. A user who misspells the name will see end marker for unknown skill "repporting" with no pointer to where in the file it is.

💡 Suggested improvement
// Compute a 1-based line number for the orphan marker
const orphanLine = content.slice(0, orphan.start).split("\n").length;
throw new Error(
  `[extractInlineSkills] end marker for unknown skill "${orphan.name}" at line ${orphanLine} (no matching start marker with that name)`
);

This small change makes the error message self-locating, which is especially useful when the file is several hundred lines long.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in e814c7c: JS orphan end-marker errors now include the line number via the shared marker helper.

// Use ../../ to escape .github/workflows and go up to the temp directory
await expect(processRuntimeImport("../../outside.md", !1, tempDir)).rejects.toThrow("Security: Path");
}),
it("should implicitly close an unterminated inline skill block so it cannot swallow spliced-in content", async () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The new processRuntimeImport tests use , (comma operator) inside it(...) — a copy-paste pattern from the surrounding pre-existing tests — but this means each new it(...) call is the second operand of a comma expression inside the outer (it(...), it(...)) chain, not a standalone test declaration. If the test runner evaluates but does not register them individually, failures can be masked.

The integration tests for closeUnterminatedInlineMarkers are the most important new tests in this PR; it is worth confirming that each it(...) here actually registers as a distinct test case rather than being swallowed by the comma-expression structure.

💡 Verification step

Run the test file with --verbose and verify all four new tests appear by name in the output:

npx jest runtime_import.test.cjs --verbose 2>&1 | grep -E "should implicitly close|should leave|should not add"

If they are missing, extract them into top-level it(...) calls (not comma-chained) to guarantee registration.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in e814c7c: the new runtime-import tests were verified by name under Vitest verbose output, and the direct marker-composition test is now a standalone suite.

Comment thread pkg/parser/inline_section_helpers.go Outdated

for ei, used := range usedEnd {
if !used {
return "", nil, fmt.Errorf("end marker for unknown section %q (no matching start marker with that name)", endMarkers[ei].name)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The orphan end-marker error omits the byte offset or line number, making diagnosis slow in large workflow files.

fmt.Errorf("end marker for unknown section %q (no matching start marker with that name)", ...) tells the author what name was wrong but not where to look.

💡 Suggested improvement
orphan := endMarkers[ei]
lineNum := 1 + strings.Count(markdown[:orphan.start], "\n")
return "", nil, fmt.Errorf(
    "end marker for unknown section %q at line %d (no matching start marker with that name)",
    orphan.name, lineNum,
)

Same improvement would benefit the JS path in extract_inline_skills.cjs.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in e814c7c: Go orphan end-marker errors now include the line number where the orphan marker was found.

* @param {string} content - Resolved content of a single runtime import (file or URL).
* @returns {string} Content with implicit skill/agent end markers made explicit.
*/
function closeUnterminatedInlineMarkers(content) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] closeUnterminatedInlineMarkers applies skill markers first, then agent markers — but closeUnterminatedSkillMarkers uses H2_HEADING_RE (which matches any ## heading) to find implicit boundaries, meaning an ## agent: \name`` heading is a valid implicit boundary for a skill block.

If a file contains an unterminated skill block immediately followed by an unterminated agent block:

## skill: `reporting`
Skill content.
## agent: `helper`
Agent content.

closeUnterminatedSkillMarkers closes the skill at the ## agent: heading (correct), then closeUnterminatedSubAgentMarkers closes the agent at EOF (correct). The composed result is fine.

This is worth a regression test to lock in this composition order and prevent a future swap from silently changing behaviour.

💡 Suggested test
it("closeUnterminatedInlineMarkers handles skill-then-agent in same file", () => {
  const content = "## skill: `reporting`\nSkill content.\n## agent: `helper`\nAgent content.\n";
  const result = closeUnterminatedInlineMarkers(content);
  expect(result).toContain("## end skill: `reporting`");
  expect(result).toContain("## end agent: `helper`");
  // skill end marker must precede agent start
  expect(result.indexOf("## end skill")).toBeLessThan(result.indexOf("## agent:"));
});

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in e814c7c: added regression coverage for an unterminated skill immediately followed by an unterminated agent, preserving that composition order.

Copilot AI and others added 2 commits August 8, 2026 19:22
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…-end-marker

# Conflicts:
#	.github/workflows/deep-report.lock.yml

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan

pelikhan commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

@copilot implicit end market between different skill/agent sections should be preserved and tested

Copilot AI commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts on this branch.

Resolved the merge conflict and pushed the merge commit 770ee8d.

Copilot AI commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Quick triage nudge for this PR.

Please refresh the branch if GitHub can update it cleanly, address the current maintainer-facing feedback, run the pr-finisher skill, and push follow-up fix...

Completed the pr-finisher pass on existing head 1aa17f5. The branch is 0 behind origin/main (make merge-main was a no-op), referenced run 31281266523 succeeded with no failed jobs, and local validation passed with make agent-report-progress. No follow-up file changes were needed; CI remains stale until a maintainer re-triggers it if required.

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

PR Triage

  • Category: feature
  • Risk: medium (104 files touched, 1428+/159-, but ~90 are regenerated .lock.yml; substantive changes limited to inline-skill/sub-agent parser + JS extractors + docs)
  • Score: 78/100 (impact 40, urgency 18, quality 20)
  • CI: all core checks passing (build, lint, unit tests, JS tests, security)
  • Recommendation: fast_track — new capability (explicit end markers for inline skills/sub-agents), well-tested, CI green, has an ADR, but is a behavior change touching parser + generated workflow files, so still warrants expedited human review before merge.

Generated by 🔧 PR Triage Agent · auto · 51 AIC · ⌖ 2.57 AIC · ⊞ 8K ·

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot Quick triage nudge for this PR.

Please refresh the branch if GitHub can update it cleanly, re-check the current maintainer-facing state, run the pr-finisher skill, and push follow-up fixes only if something actionable remains.

Open review context (newest first):

  • Recent review follow-up Re-confirm whether anything maintainer-facing remains beyond the prior follow-up responses and green CI, then run pr-finisher and push only if further fixes are needed.

Branch refresh was requested.

Run: https://github.com/github/gh-aw/actions/runs/31287357931

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 20.7 AIC · ⌖ 6.68 AIC · ⊞ 8.5K ·
Comment /souschef to run again

Copilot AI commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Quick triage nudge for this PR.

Please refresh the branch if GitHub can update it cleanly, re-check the current maintainer-facing state, run the pr-finisher skill, and push follow-up fixes...

Completed the pr-finisher recheck on existing head f0d5e98. The branch is 0 behind origin/main (make merge-main was a no-op), referenced run 31287357931 had no failed jobs, and local validation passed with make agent-report-progress. I found no additional maintainer-facing fixes to push.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot Please refresh this branch if needed, address any remaining review feedback, and run the pr-finisher skill.

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 3.76 AIC · ⌖ 6.55 AIC · ⊞ 8.5K ·
Comment /souschef to run again

Copilot AI and others added 2 commits August 9, 2026 04:11
…-end-marker

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Please refresh this branch if needed, address any remaining review feedback, and run the pr-finisher skill.

Generated by [👨‍🍳 PR Sous Chef](https://github.com/github/gh-aw/actions/...

Addressed in b3dcefb: refreshed the branch with latest origin/main, regenerated the workflow lockfiles, ran pr-finisher validation (make agent-report-progress), checked the referenced PR Sous Chef run logs (no failed jobs), and pushed the follow-up.

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

PR Triage

  • Category: feature
  • Risk: high
  • Priority: high
  • Score: 67/100 (impact 40 + urgency 15 + quality 12)
  • Recommended action: fast_track

Large new syntax feature (2843 lines), partially approved but blocked, no CI - high value, needs priority review.

Generated by 🔧 PR Triage Agent · auto · 58.3 AIC · ⌖ 2.48 AIC · ⊞ 8K ·

@pelikhan
pelikhan merged commit 08f602f into main Aug 9, 2026
37 checks passed
@pelikhan
pelikhan deleted the copilot/update-parser-end-marker branch August 9, 2026 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants