diff --git a/.pdd/meta/sync_order_python.json b/.pdd/meta/sync_order_python.json new file mode 100644 index 0000000000..4f0ead9b5b --- /dev/null +++ b/.pdd/meta/sync_order_python.json @@ -0,0 +1,16 @@ +{ + "pdd_version": "0.0.298.dev0", + "timestamp": "2026-07-10T06:09:15.384060+00:00", + "command": "fix", + "prompt_hash": "2aefd06c3a9bdf2c2fc30dcafd174edf7820c33fa56ff40c9826009008c644bb", + "code_hash": "22dec5209b81b3ab64575f541212c85b86b534844db64259a71d8d8d18daf750", + "example_hash": null, + "test_hash": null, + "test_files": null, + "include_deps": { + "context/agentic_common_example.py": "c1538a115a3a33da228e7f6cc048f2a99023cd2c83a0efef382e49c477b24ad3", + "context/architecture_sync_example.py": "b6158dbc7ca3fd32665528562225f6739ec521a071d845acab0f7caaea221ae0", + "context/auto_include_example.py": "0c278ed716298149777bc7082827eb8aa6d80dac264c66b6cded6871232f2df7", + "context/python_preamble.prompt": "0388ed131bf986f8752e1bc4c81e4da0460cfe2908ec8c60b1314edbab768254" + } +} \ No newline at end of file diff --git a/pdd/prompts/sync_order_python.prompt b/pdd/prompts/sync_order_python.prompt index 4b87bc09fa..4d9513835b 100644 --- a/pdd/prompts/sync_order_python.prompt +++ b/pdd/prompts/sync_order_python.prompt @@ -16,7 +16,7 @@ A utility module that parses `` tags from prompt files, builds a depend - bare body: `path` - attributed body: `path` (or any other attribute — discovery doesn't inspect them, just allows them on the opening tag) - self-closing: `` - - Body-form regex: `r']*?))?(?(.*?)'` with `re.DOTALL`, capturing the optional attribute string so the parser can honor a `path=` attribute on attributed body includes. The `(?` negative lookbehind is required so a self-closing `` is NOT picked up by the body-form regex (without it, the body-form would absorb everything between the self-closing tag and the next ``, dropping inner includes entirely). + - Body-form regex: `r']*?))?(?((?:(?!'` with `re.DOTALL`, capturing the optional attribute string so the parser can honor a `path=` attribute on attributed body includes. The `(?` negative lookbehind is required so a self-closing `` is NOT picked up by the body-form regex. The tempered body MUST reject any match that crosses another `` `` can pair with a later real closing tag and turn hundreds of lines of prompt prose into a bogus path. - Self-closing regex: `r']*?)\s*/>'` with `re.DOTALL`, then extract the `path` attribute via `r'path\s*=\s*["\']([^"\']+)["\']'` from the captured attrs. - `` body regex: `r']*?)?>(.*?)'` (attributes optional on the opening tag). - For `` payload, mirror `pdd.preprocess.process_include_many_tags`: split on newlines first, then on commas within each line, strip each piece, drop empties. Both separators must be supported because real prompts write the list either inline (`a, b, c`) or one-per-line (`\na\nb\nc\n`). diff --git a/pdd/sync_order.py b/pdd/sync_order.py index 0949b99f37..c3e640754f 100644 --- a/pdd/sync_order.py +++ b/pdd/sync_order.py @@ -54,7 +54,13 @@ def extract_includes_from_file(file_path: Path) -> Set[str]: # - self-closing: ```` # Real prompts use all three; missing any one means a real PDD # include form sits outside #739's safety net. - # Body-form must exclude self-closing ``. Without + # Body-form must exclude self-closing `` and must not + # cross another include opener. Without the tempered body match, an + # inline documentation token such as `` `` `` can consume + # everything through a later real ```` and surface hundreds + # of lines as a bogus filesystem path. + # + # Without # the `(?` lookbehind, the body-form regex would absorb the # entire `\nfoo.md` span as one # match, losing the inner include and producing garbage. @@ -68,7 +74,9 @@ def extract_includes_from_file(file_path: Path) -> Set[str]: # actually resolves it as ``docs/source.md`` — and the scope # guard's allowlist would diverge from the real include graph. single_matches = re.findall( - r']*?))?(?(.*?)', content, re.DOTALL + r']*?))?(?((?:(?!', + content, + re.DOTALL, ) for attrs, body in single_matches: path_value: Optional[str] = None diff --git a/tests/test_sync_order.py b/tests/test_sync_order.py index 75d850f8b6..6c5e1e7359 100644 --- a/tests/test_sync_order.py +++ b/tests/test_sync_order.py @@ -89,6 +89,20 @@ def test_extract_includes_body_form_no_path_attr_uses_body(tmp_path): includes = sync_order.extract_includes_from_file(f) assert includes == {"docs/source.md"} +def test_extract_includes_does_not_span_inline_documentation_token(tmp_path): + """An inline `` mention must not consume a later real include.""" + f = tmp_path / "test.prompt" + f.write_text( + "Use `` tags to expand context.\n" + "\n" + " context/example.py\n" + "\n", + encoding="utf-8", + ) + + includes = sync_order.extract_includes_from_file(f) + assert includes == {"context/example.py"} + # ============================================================================== # Unit Tests: extract_module_from_include # ==============================================================================