Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license

This commit is contained in:
2026-09-05 13:26:46 +03:00
commit 03634b1ca3
11340 changed files with 3442369 additions and 0 deletions
View File
+45
View File
@@ -0,0 +1,45 @@
# Crash/resume persistence conformance cells
Phase 1 of the machine-checked conformance suite proposed in #80921, following
the contract framing of "Resume Means Resume" (arXiv:2608.03836): each cell is
a deterministic, LLM-free probe of one persistence contract clause, run against
the **real `SessionDB`** with a real `SIGKILL` delivered to a separate OS
process mid-write.
## Cells
| cell | contract clause | origin |
|---|---|---|
| 1 — `test_cell1_prefix_durability` | acknowledged appends survive a hard crash; contiguous prefix; deterministic recovery | adapted from the tracking issue's spot-probe (29.5K-message original, scaled to a ≥200-append kill window with identical assertions) |
| 2 — `test_cell2_consume_once` | a parked handoff is claimed by exactly one of N racing processes | adapted from the tracking issue's spot-probe (8-process file-barrier race) |
| 3 — `test_cell3_rotation_atomicity` | a compression rotation is visible entirely or not at all — never a compression-ended parent without a continuation (the #80337 orphan shape; recovery for the legacy population merged in #80487) | new in this suite |
| 4 — fork determinism on edit/rewind | recovery yields exactly the chosen prefix after a fork | **stub** — interlocked with the rewind/archive redesign (#82956#82959) |
| 5 — delivery-outbox effect exactly-once | crash between provider send and durable record must not double-deliver on catch-up | **stub** — needs a fake-transport seam; cron delivery scope in flight (#83197/#83557) |
## Method
- Real `SessionDB(db_path=...)` in an isolated `tmp_path`; no mocks on the
persistence layer.
- Crashes are real `SIGKILL`s to a separate interpreter, asserted to be
**alive at kill time** (a clean early exit cannot masquerade as a crash
test); acknowledgement journals tolerate a torn final line (the kill can
interrupt the journal write itself).
- Every wait is deadline-bounded; coordination uses file barriers, never
sleeps-for-correctness.
- Journal-mode matrix (cells 1 and 3): the resolver's default, explicit
`DELETE`, and explicit `WAL` — each leg steers the child's own resolver
via an isolated `HERMES_HOME` config, then **audits the on-disk mode after
the run** and skips when the environment didn't honor the request (e.g.
the resolver's WAL-reset downgrade gate, the tracking issue's 3.50.4
caveat). A leg that ran in a different mode never counts as evidence for
the advertised one. Cell 2 runs on the resolver's default only (the
consume-once property is journal-mode-independent: it rests on a single
predicated UPDATE).
## Semantics
These are **conformance** cells: they are expected GREEN on main (cells 12
reproduce the tracking issue's passing probes; cell 3 pins the atomicity the
#80337 forensics established). A failing cell is a **fire**: report it on
#80921 with the cell's evidence — do not silence it, and do not attach a fix
to this suite.
+159
View File
@@ -0,0 +1,159 @@
"""Shared harness for the crash/resume persistence conformance cells (#80921).
Method (per the spot-probes in the tracking issue): real ``SessionDB``
against an isolated temp database, real ``SIGKILL`` delivered to a separate
OS process mid-write, deterministic and LLM-free. Every wait has a hard
deadline so a wedged child can never hang the suite; coordination uses file
barriers, never bare sleeps.
Journal-mode policy mirrors the issue's caveat: cells run on the mode the
repo's own ``resolve_journal_mode()`` selects for this interpreter/filesystem
(recorded per cell), plus an explicit ``DELETE`` run; an explicit ``WAL`` run
is attempted and skipped when the resolver's downgrade gates trip (e.g. the
WAL-reset interpreter bug), so WAL semantics are probed exactly where they
are actually deployable.
"""
from __future__ import annotations
import os
import signal
import sqlite3
import subprocess
import sys
import time
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[3]
# Generous deadlines: xdist-loaded CI boxes stall; correctness never depends
# on these being tight, they only bound a hung child.
CHILD_DEADLINE = 60.0
POLL_INTERVAL = 0.02
def spawn_child(script_body: str, *, cwd: Path | None = None, env: dict | None = None) -> subprocess.Popen:
"""Run ``script_body`` in a fresh interpreter with the repo importable."""
child_env = dict(os.environ)
# Prepend, don't clobber: CI images may rely on an inherited PYTHONPATH
# for dependencies — losing it would fail child imports while the parent
# collects fine, surfacing only as an opaque wait_for deadline.
inherited = child_env.get("PYTHONPATH")
child_env["PYTHONPATH"] = (
f"{REPO_ROOT}{os.pathsep}{inherited}" if inherited else str(REPO_ROOT)
)
child_env["PYTHONUNBUFFERED"] = "1"
if env:
child_env.update(env)
return subprocess.Popen(
[sys.executable, "-c", script_body],
cwd=str(cwd or REPO_ROOT),
env=child_env,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
def wait_for(
predicate,
*,
deadline: float = CHILD_DEADLINE,
what: str = "condition",
child: "subprocess.Popen | None" = None,
) -> None:
"""Poll ``predicate`` until true or fail loudly at the deadline.
When ``child`` is given and it exits before the predicate turns true,
fail IMMEDIATELY with its captured stderr — a crashed writer must be an
instant diagnostic, not a 60s opaque deadline.
"""
end = time.monotonic() + deadline
while time.monotonic() < end:
if predicate():
return
if child is not None and child.poll() is not None:
err = b""
if child.stderr is not None:
err = child.stderr.read() or b""
raise AssertionError(
f"child exited early (rc={child.returncode}) while waiting "
f"for {what}; stderr:\n{err.decode(errors='replace')[-2000:]}"
)
time.sleep(POLL_INTERVAL)
raise AssertionError(f"deadline ({deadline}s) waiting for {what}")
def kill9_and_reap(proc: subprocess.Popen, *, deadline: float = CHILD_DEADLINE) -> None:
"""SIGKILL ``proc`` and reap it within ``deadline``."""
try:
proc.kill() # SIGKILL on POSIX
except ProcessLookupError:
pass
proc.wait(timeout=deadline)
def reap(proc: subprocess.Popen, *, deadline: float = CHILD_DEADLINE) -> tuple[int, str, str]:
"""Wait for a child to exit on its own; kill + fail if it doesn't."""
try:
out, err = proc.communicate(timeout=deadline)
except subprocess.TimeoutExpired:
proc.kill()
out, err = proc.communicate(timeout=10)
raise AssertionError(
f"child did not exit within {deadline}s; stderr:\n"
f"{err.decode(errors='replace')[-2000:]}"
)
return proc.returncode, out.decode(errors="replace"), err.decode(errors="replace")
def on_disk_journal_mode(db_path: Path) -> str:
"""Record the journal mode actually in effect for a cell result."""
conn = sqlite3.connect(str(db_path))
try:
row = conn.execute("PRAGMA journal_mode").fetchone()
return str(row[0]) if row else "unknown"
finally:
conn.close()
def integrity_ok(db_path: Path) -> bool:
conn = sqlite3.connect(str(db_path))
try:
row = conn.execute("PRAGMA integrity_check").fetchone()
return bool(row) and str(row[0]).lower() == "ok"
finally:
conn.close()
def make_hermes_home(base: Path, journal_mode: str) -> Path:
"""Create an isolated HERMES_HOME whose config pins ``database.journal_mode``.
The journal-mode matrix legs must steer the CHILD's own resolver:
pre-seeding the DB file alone is not enough, because ``SessionDB.__init__``
runs ``apply_wal_with_fallback()`` which upgrades a non-WAL file to WAL
whenever the configured mode (default ``wal``) says so — on healthy
SQLite the DELETE leg would silently run in WAL.
"""
home = base / f"hermes-home-{journal_mode}"
home.mkdir(parents=True, exist_ok=True)
(home / "config.yaml").write_text(
f"database:\n journal_mode: {journal_mode}\n", encoding="utf-8"
)
return home
def effective_mode_or_skip(db_path: Path, requested_mode: str | None) -> str:
"""Record the on-disk journal mode; skip if a requested leg wasn't honored.
A leg that ran in a different mode than advertised must never count as
green evidence for the advertised mode.
"""
import pytest
mode = on_disk_journal_mode(db_path)
if requested_mode is not None and mode.upper() != requested_mode.upper():
pytest.skip(
f"journal_mode={requested_mode} not honored by this environment "
f"(effective {mode}) — matrix leg not probeable here"
)
return mode
@@ -0,0 +1,141 @@
"""Cell 1 — prefix continuation + recovery determinism under real SIGKILL.
Contract clause (arXiv:2608.03836): every append the store *acknowledged*
survives a hard crash; recovery yields a contiguous prefix (no holes, no
duplicates); two independent recovery passes see the identical transcript.
Adapted from the spot-probe in the tracking issue (#80921), which ran ~29.5K
messages to a SIGKILL with zero lost-after-return. Scaled down for CI: the
parent kills the writer once >= 200 acknowledged appends are journaled — the
property assertions are identical, only the exposure window is shorter.
"""
from __future__ import annotations
import json
import sqlite3
from pathlib import Path
import pytest
from tests.conformance.persistence._harness import (
effective_mode_or_skip,
integrity_ok,
kill9_and_reap,
make_hermes_home,
spawn_child,
wait_for,
)
WRITER = r"""
import json, sys
from pathlib import Path
from hermes_state import SessionDB
db_path = Path({db_path!r})
journal = Path({journal!r})
db = SessionDB(db_path=db_path)
db.create_session("cell1", source="conformance")
i = 0
with journal.open("a", buffering=1) as j:
while True:
rowid = db.append_message("cell1", "user", content=f"m{{i}}")
# fsync-journal the acknowledged index AFTER append returns —
# exactly the probe's definition of "claimed durable".
j.write(json.dumps({{"i": i, "rowid": rowid}}) + "\n")
j.flush()
i += 1
"""
def _acknowledged(journal: Path) -> list[dict]:
if not journal.exists():
return []
out = []
for line in journal.read_text().splitlines():
try:
out.append(json.loads(line))
except json.JSONDecodeError:
# A torn final line is expected under SIGKILL: the write to the
# journal itself was interrupted. That index was never fully
# acknowledged to the harness, so it is out of scope.
continue
return out
def _recover(db_path: Path) -> list[tuple]:
"""One independent recovery pass in a fresh connection/process context."""
conn = sqlite3.connect(str(db_path))
try:
return conn.execute(
"SELECT id, content FROM messages WHERE session_id='cell1' ORDER BY id"
).fetchall()
finally:
conn.close()
@pytest.mark.parametrize("requested_mode", [None, "DELETE", "WAL"])
def test_acknowledged_appends_survive_sigkill(tmp_path, requested_mode):
db_path = tmp_path / "state.db"
journal = tmp_path / "acked.jsonl"
child_env = {}
if requested_mode is not None:
# Steer the CHILD's own resolver via an isolated HERMES_HOME config:
# pre-seeding the file alone is not enough — SessionDB.__init__ runs
# apply_wal_with_fallback(), which upgrades a non-WAL file to WAL
# whenever the configured mode says so (the resolver's downgrade
# gates may still refuse; effective_mode_or_skip audits post-run).
child_env["HERMES_HOME"] = str(
make_hermes_home(tmp_path, requested_mode.lower())
)
child = spawn_child(
WRITER.format(db_path=str(db_path), journal=str(journal)), env=child_env
)
try:
wait_for(
lambda: len(_acknowledged(journal)) >= 200,
what=">=200 acknowledged appends",
child=child,
)
# The kill must interrupt a LIVE writer — a child that already
# exited would turn this into a clean-shutdown test.
assert child.poll() is None, (
f"writer exited early (rc={child.returncode}): "
f"{(child.stderr.read() if child.stderr else b'').decode(errors='replace')[-1500:]}"
)
finally:
kill9_and_reap(child)
# A leg that ran in a different mode than requested is no evidence for
# the requested mode — skip it rather than silently double-counting WAL.
mode = effective_mode_or_skip(db_path, requested_mode)
acked = _acknowledged(journal)
assert len(acked) >= 200, (
f"[journal_mode={mode}] only {len(acked)} acknowledged appends "
"journaled before the kill — harness window too small"
)
pass1 = _recover(db_path)
pass2 = _recover(db_path)
# Zero lost-after-return: every acknowledged index is present.
recovered_contents = {row[1] for row in pass1}
lost = [a for a in acked if f"m{a['i']}" not in recovered_contents]
assert not lost, (
f"[journal_mode={mode}] {len(lost)} acknowledged appends lost after "
f"SIGKILL (first: {lost[:3]})"
)
# Contiguous prefix: indices 0..N-1 with no holes and no duplicates.
indices = sorted(int(row[1][1:]) for row in pass1)
assert indices == list(range(len(indices))), (
f"[journal_mode={mode}] recovered transcript is not a contiguous "
"prefix (holes or duplicates present)"
)
# Recovery determinism: two independent passes identical.
assert pass1 == pass2, f"[journal_mode={mode}] recovery passes diverge"
assert integrity_ok(db_path), f"[journal_mode={mode}] integrity_check failed"
@@ -0,0 +1,92 @@
"""Cell 2 — consume-once under cross-process concurrent delivery.
Contract clause (arXiv:2608.03836): a parked handoff is claimed by exactly
one consumer, no matter how many independent processes race for it. This is
the cell the paper found failing at saturation 1.0 in 36/40 cells across
deployed frameworks; Hermes' ``claim_handoff`` ships the paper's own repair
shape (single UPDATE with a state predicate, rowcount-checked), which the
tracking-issue probe confirmed. This cell pins it permanently.
8 independent OS processes are released from a file barrier simultaneously;
each calls ``SessionDB.claim_handoff()`` on the same pending session.
"""
from __future__ import annotations
from tests.conformance.persistence._harness import (
on_disk_journal_mode,
reap,
spawn_child,
wait_for,
)
CLAIMANT = r"""
import sys, time
from pathlib import Path
from hermes_state import SessionDB
db_path = Path({db_path!r})
barrier = Path({barrier!r})
ready = Path({ready!r})
ready.touch()
deadline = time.monotonic() + 55
while not barrier.exists():
if time.monotonic() > deadline:
sys.exit(3)
time.sleep(0.005)
db = SessionDB(db_path=db_path)
won = db.claim_handoff("cell2")
# Disjoint codes: 0=won, 10=lost. An unhandled exception exits 1, which must
# NEVER be confusable with a clean "lost the claim" — a run where one
# claimant wins and seven CRASH is not a consume-once proof.
sys.exit(0 if won else 10)
"""
N_CLAIMANTS = 8
def test_exactly_one_claimant_wins(tmp_path):
from hermes_state import SessionDB
db_path = tmp_path / "state.db"
barrier = tmp_path / "go"
db = SessionDB(db_path=db_path)
db.create_session("cell2", source="conformance")
assert db.request_handoff("cell2", "telegram") is not False
children = []
ready_files = []
for i in range(N_CLAIMANTS):
ready = tmp_path / f"ready-{i}"
ready_files.append(ready)
children.append(
spawn_child(
CLAIMANT.format(
db_path=str(db_path), barrier=str(barrier), ready=str(ready)
)
)
)
# Barrier: release only when every process is up and polling.
wait_for(
lambda: all(r.exists() for r in ready_files),
what="all claimants at the barrier",
)
barrier.touch()
results = [reap(c) for c in children]
mode = on_disk_journal_mode(db_path)
codes = [rc for rc, _, _ in results]
assert all(rc in (0, 10) for rc in codes), (
f"[journal_mode={mode}] claimant crashed/timed out: {codes}; "
f"stderr: {[e[-300:] for _, _, e in results if e]}"
)
winners = codes.count(0)
assert winners == 1, (
f"[journal_mode={mode}] consume-once violated: {winners} of "
f"{N_CLAIMANTS} concurrent claimants won"
)
@@ -0,0 +1,159 @@
"""Cell 3 — crash mid-compression-rotation: the atomic-publication contract.
Contract clause: a compression rotation (close parent + publish continuation
child + write compacted handoff) is visible **entirely or not at all**. A hard
crash at any point must never yield an orphan — a parent ended with
``end_reason='compression'`` and no continuation child — because that is the
state every reader treats as unreachable (the P1 in #80337; the recovery
merged in #80487 exists to drain the pre-atomicity population of exactly
these rows).
The forensics on #80337 established the contract holds architecturally on
current main (``publish_compression_child`` runs parent-close + child-insert
+ handoff in one transaction on one handle). This cell pins it empirically:
a writer process performs rotations in a tight loop through the REAL leased
path (``try_acquire_compression_lock`` → ``publish_compression_child``) and
is SIGKILLed mid-loop; recovery then audits every rotation for atomicity.
"""
from __future__ import annotations
import json
import sqlite3
from pathlib import Path
import pytest
from tests.conformance.persistence._harness import (
effective_mode_or_skip,
integrity_ok,
kill9_and_reap,
make_hermes_home,
spawn_child,
wait_for,
)
ROTATOR = r"""
import json, sys
from pathlib import Path
from hermes_state import SessionDB
db_path = Path({db_path!r})
journal = Path({journal!r})
db = SessionDB(db_path=db_path)
i = 0
with journal.open("a", buffering=1) as j:
while True:
parent = f"parent-{{i}}"
child = f"child-{{i}}"
db.create_session(parent, source="conformance")
db.append_message(parent, "user", content="pre-rotation turn")
holder = f"cell3:pid={{__import__('os').getpid()}}"
assert db.try_acquire_compression_lock(parent, holder)
db.publish_compression_child(
parent_session_id=parent,
child_session_id=child,
source="conformance",
messages=[{{"role": "user", "content": "compacted handoff"}}],
compression_lock_holder=holder,
)
j.write(json.dumps({{"i": i}}) + "\n")
j.flush()
i += 1
"""
def _completed_rotations(journal: Path) -> int:
if not journal.exists():
return 0
n = 0
for line in journal.read_text().splitlines():
try:
json.loads(line)
n += 1
except json.JSONDecodeError:
continue # torn final line under SIGKILL — unacknowledged
return n
@pytest.mark.parametrize("requested_mode", [None, "DELETE", "WAL"])
def test_rotation_is_atomic_under_sigkill(tmp_path, requested_mode):
db_path = tmp_path / "state.db"
journal = tmp_path / "rotations.jsonl"
child_env = {}
if requested_mode is not None:
# Steer the CHILD's own resolver via an isolated HERMES_HOME config:
# pre-seeding the file alone is not enough — SessionDB.__init__ runs
# apply_wal_with_fallback(), which upgrades a non-WAL file to WAL
# whenever the configured mode says so (the resolver's downgrade
# gates may still refuse; effective_mode_or_skip audits post-run).
child_env["HERMES_HOME"] = str(
make_hermes_home(tmp_path, requested_mode.lower())
)
child = spawn_child(
ROTATOR.format(db_path=str(db_path), journal=str(journal)), env=child_env
)
try:
wait_for(
lambda: _completed_rotations(journal) >= 50,
what=">=50 completed rotations",
child=child,
)
assert child.poll() is None, (
f"rotator exited early (rc={child.returncode}): "
f"{(child.stderr.read() if child.stderr else b'').decode(errors='replace')[-1500:]}"
)
finally:
kill9_and_reap(child)
# A leg that ran in a different mode than requested is no evidence for
# the requested mode — skip it rather than silently double-counting WAL.
mode = effective_mode_or_skip(db_path, requested_mode)
acked = _completed_rotations(journal)
assert acked >= 50, (
f"[journal_mode={mode}] only {acked} rotations acknowledged before "
"the kill — harness window too small"
)
conn = sqlite3.connect(str(db_path))
try:
# THE contract: no compression-ended parent may lack a child row.
orphans = conn.execute(
"""
SELECT p.id FROM sessions p
WHERE p.end_reason = 'compression'
AND NOT EXISTS (
SELECT 1 FROM sessions c WHERE c.parent_session_id = p.id
)
"""
).fetchall()
assert not orphans, (
f"[journal_mode={mode}] atomicity violated: {len(orphans)} "
f"compression-ended parent(s) with no continuation "
f"({[o[0] for o in orphans[:5]]}) — the #80337 orphan shape"
)
# Completeness the other way: every acknowledged rotation is fully
# visible (parent ended AND child present).
for i in range(acked):
parent_row = conn.execute(
"SELECT end_reason FROM sessions WHERE id = ?",
(f"parent-{i}",),
).fetchone()
child_row = conn.execute(
"SELECT id FROM sessions WHERE id = ?", (f"child-{i}",)
).fetchone()
assert parent_row and parent_row[0] == "compression" and child_row, (
f"[journal_mode={mode}] acknowledged rotation {i} not fully "
f"visible after recovery (parent={parent_row}, child={child_row})"
)
# The interrupted trailing rotation (if any) must be all-or-nothing:
# either invisible or complete — checked by the orphan query above.
finally:
conn.close()
assert integrity_ok(db_path), f"[journal_mode={mode}] integrity_check failed"
@@ -0,0 +1,47 @@
"""Wave-2 cell stubs — contract clauses named, implementations interlocked.
These are deliberate ``pytest.skip`` placeholders, not TODOs: each names the
exact contract clause it will pin and the reason it is not implemented in the
skeleton PR. See the tracking issue (#80921) for the full ~39-cell matrix.
"""
from __future__ import annotations
import pytest
def test_cell4_fork_determinism_on_rewind_stub():
"""Cell 4 — fork determinism on the edit/rewind paths.
Contract clause: after an edit/rewind fork, recovery yields exactly the
chosen prefix (no resurrection of superseded turns, no archived-copy
duplication), deterministically across independent recovery passes.
Deliberately deferred: the rewind/archive semantics this cell would pin
are being actively redesigned in #82956#82959 (durable row-id
addressing, archive-mode dedup, /retry archive_drop plumbing). Writing
the cell against today's behavior would test a moving target; it lands
as that cluster's conformance check once the contract settles.
"""
pytest.skip(
"wave 2: interlocked with the rewind/archive redesign "
"(#82956-#82959) — cell lands as that cluster's conformance check"
)
def test_cell5_delivery_outbox_exactly_once_stub():
"""Cell 5 — effect exactly-once across the delivery outbox boundary.
Contract clause: a crash between provider send and durable record must
not double-deliver on catch-up (cron ticker restart, gateway reboot) —
the cell the paper (arXiv:2608.03836) probes as 'effect exactly-once',
distinct from cell 2's consume-once (claim vs side-effect).
Deliberately deferred: requires a deterministic fake-transport seam for
the delivery path (the send must be observable without a live adapter);
the cron delivery-scope interplay is also in flight (#83197/#83557).
"""
pytest.skip(
"wave 2: needs a deterministic fake-transport seam; cron delivery "
"scope fixes in flight (#83197/#83557)"
)
@@ -0,0 +1,95 @@
"""Conformance vector generator tests (Phase 5 oracle workstream).
Behavior contracts, not change-detectors: determinism, corpus invariants,
oracle-import health (the generator calls format_message UNBOUND — these
tests fail loudly if a refactor gives those renderers instance state), and
vector-file shape. Native outputs themselves are NOT snapshotted here — the
connector's conformance runner is the consumer that asserts them.
"""
from __future__ import annotations
import json
import re
import sys
from pathlib import Path
import pytest
REPO_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(REPO_ROOT / "scripts"))
from generate_conformance_vectors import ( # noqa: E402
ADVERSARIAL,
GRID,
SCAR,
_oracles,
corpus,
generate,
)
PLATFORMS = ("discord", "slack", "telegram", "whatsapp")
def test_corpus_ids_unique_and_categorized():
rows = corpus()
ids = [r["id"] for r in rows]
assert len(ids) == len(set(ids)), "vector ids must be unique (runner keys on them)"
assert {r["category"] for r in rows} == {"grid", "scar", "adversarial"}
assert len(GRID) >= 20 and len(SCAR) >= 10 and len(ADVERSARIAL) >= 8
def test_oracles_importable_and_self_free():
"""The generator invokes format_message unbound (self=None) — verify every
oracle actually renders under that calling convention. A refactor that
adds instance state to a renderer must update the generator too."""
oracles = _oracles()
assert set(oracles) == set(PLATFORMS)
for platform, render in oracles.items():
out = render("**bold** and `code`")
assert isinstance(out, str) and out, platform
def test_vector_files_shape(tmp_path):
generate(tmp_path)
for platform in PLATFORMS:
doc = json.loads((tmp_path / f"{platform}.json").read_text(encoding="utf-8"))
assert doc["platform"] == platform
assert doc["oracle"]["repo"] == "NousResearch/hermes-agent"
assert re.match(r"^[0-9a-f]{40}$|^unknown$", doc["oracle"]["commit"])
assert doc["oracle"]["generator_version"] >= 1
ids = set()
for v in doc["vectors"]:
assert v["expect"] in ("parity", "semantic", "divergent"), v["id"]
assert isinstance(v["native_output"], str)
if v["expect"] == "divergent":
assert v.get("note"), f"{platform}/{v['id']}: divergent needs a note"
ids.add(v["id"])
assert len(ids) == len(doc["vectors"])
def test_committed_vectors_match_regeneration(tmp_path):
"""The committed tests/conformance/vectors/ must reproduce from the
current oracle — the same lockstep discipline as openapi.json (drift
means someone changed a renderer without regenerating)."""
committed_dir = REPO_ROOT / "tests" / "conformance" / "vectors"
if not committed_dir.exists():
pytest.skip("no committed vectors in this checkout")
generate(tmp_path)
for platform in PLATFORMS:
fresh = json.loads((tmp_path / f"{platform}.json").read_text(encoding="utf-8"))
committed = json.loads((committed_dir / f"{platform}.json").read_text(encoding="utf-8"))
# Compare everything except the commit stamp (committed file may be
# one commit behind HEAD in a dirty working tree).
fresh["oracle"].pop("commit")
committed["oracle"].pop("commit")
assert fresh == committed, (
f"{platform} vectors drifted — run "
"`python scripts/generate_conformance_vectors.py` and commit"
)
+322
View File
@@ -0,0 +1,322 @@
{
"$comment": "GENERATED — do not hand-edit. Regenerate with hermes-agent scripts/generate_conformance_vectors.py; the native renderers are the oracle (executable spec).",
"oracle": {
"repo": "NousResearch/hermes-agent",
"commit": "40eebc7d70f3d8e95c429c8aa482f31ba6c867f6",
"generator": "scripts/generate_conformance_vectors.py",
"generator_version": 1
},
"platform": "discord",
"vectors": [
{
"id": "plain-text",
"category": "grid",
"expect": "parity",
"input": "Just a plain sentence.",
"native_output": "Just a plain sentence."
},
{
"id": "bold",
"category": "grid",
"expect": "parity",
"input": "This is **bold** text.",
"native_output": "This is **bold** text."
},
{
"id": "italic",
"category": "grid",
"expect": "parity",
"input": "This is *italic* text.",
"native_output": "This is *italic* text."
},
{
"id": "bold-italic",
"category": "grid",
"expect": "parity",
"input": "Mix of **bold** and *italic* in one line.",
"native_output": "Mix of **bold** and *italic* in one line."
},
{
"id": "strikethrough",
"category": "grid",
"expect": "parity",
"input": "This is ~~struck~~ text.",
"native_output": "This is ~~struck~~ text."
},
{
"id": "inline-code",
"category": "grid",
"expect": "parity",
"input": "Run `pip install hermes` to start.",
"native_output": "Run `pip install hermes` to start."
},
{
"id": "fenced-code",
"category": "grid",
"expect": "parity",
"input": "```\nprint('hello')\n```",
"native_output": "```\nprint('hello')\n```"
},
{
"id": "fenced-code-lang",
"category": "grid",
"expect": "parity",
"input": "```python\ndef f(x):\n return x * 2\n```",
"native_output": "```python\ndef f(x):\n return x * 2\n```"
},
{
"id": "link",
"category": "grid",
"expect": "parity",
"input": "See [the docs](https://example.com/docs) for more.",
"native_output": "See [the docs](https://example.com/docs) for more."
},
{
"id": "link-parens-url",
"category": "grid",
"expect": "parity",
"input": "See [spec](https://example.com/a_(b)) here.",
"native_output": "See [spec](https://example.com/a_(b)) here."
},
{
"id": "header-h1",
"category": "grid",
"expect": "parity",
"input": "# Big Title\nBody follows.",
"native_output": "# Big Title\nBody follows."
},
{
"id": "header-h2",
"category": "grid",
"expect": "parity",
"input": "## Section\nBody follows.",
"native_output": "## Section\nBody follows."
},
{
"id": "header-h3",
"category": "grid",
"expect": "parity",
"input": "### Sub-section\nBody follows.",
"native_output": "### Sub-section\nBody follows."
},
{
"id": "ul-list",
"category": "grid",
"expect": "parity",
"input": "- first\n- second\n- third",
"native_output": "- first\n- second\n- third"
},
{
"id": "ol-list",
"category": "grid",
"expect": "parity",
"input": "1. first\n2. second\n3. third",
"native_output": "1. first\n2. second\n3. third"
},
{
"id": "nested-list",
"category": "grid",
"expect": "parity",
"input": "- outer\n - inner one\n - inner two\n- outer two",
"native_output": "- outer\n - inner one\n - inner two\n- outer two"
},
{
"id": "blockquote",
"category": "grid",
"expect": "parity",
"input": "> quoted wisdom\nregular line",
"native_output": "> quoted wisdom\nregular line"
},
{
"id": "hrule",
"category": "grid",
"expect": "parity",
"input": "above\n\n---\n\nbelow",
"native_output": "above\n\n---\n\nbelow"
},
{
"id": "table-simple",
"category": "grid",
"expect": "divergent",
"input": "| name | value |\n|------|-------|\n| a | 1 |\n| b | 2 |",
"native_output": "**a**\n• value: 1\n\n**b**\n• value: 2",
"note": "native converts GFM tables to bullet groups; connector passes raw markdown through (port deferred — parity report Phase 4/oracle section)"
},
{
"id": "emoji",
"category": "grid",
"expect": "parity",
"input": "Done ✅ with 🎉 emoji 👀 test.",
"native_output": "Done ✅ with 🎉 emoji 👀 test."
},
{
"id": "cjk",
"category": "grid",
"expect": "parity",
"input": "中文测试:**粗体** 和 `代码` 混排。",
"native_output": "中文测试:**粗体** 和 `代码` 混排。"
},
{
"id": "bare-url",
"category": "grid",
"expect": "parity",
"input": "Visit https://example.com/path?q=1&r=2 today.",
"native_output": "Visit https://example.com/path?q=1&r=2 today."
},
{
"id": "mixed-document",
"category": "grid",
"expect": "parity",
"input": "## Report\n\nStatus: **green**. Details in `runbook.md`.\n\n- item *one*\n- item **two**\n\n```sh\nmake deploy\n```\n\nSee [dashboard](https://grafana.example.com/d/x).",
"native_output": "## Report\n\nStatus: **green**. Details in `runbook.md`.\n\n- item *one*\n- item **two**\n\n```sh\nmake deploy\n```\n\nSee [dashboard](https://grafana.example.com/d/x)."
},
{
"id": "mdv2-reserved-chars",
"category": "scar",
"expect": "parity",
"input": "Price is 3.50 (was 4.00) — save ~12%! #deal +tax = win.",
"native_output": "Price is 3.50 (was 4.00) — save ~12%! #deal +tax = win."
},
{
"id": "mdv2-underscores",
"category": "scar",
"expect": "parity",
"input": "snake_case_name and file_name.py in prose.",
"native_output": "snake_case_name and file_name.py in prose."
},
{
"id": "mdv2-brackets",
"category": "scar",
"expect": "parity",
"input": "Array[0] and dict{key} and (parens) live here.",
"native_output": "Array[0] and dict{key} and (parens) live here."
},
{
"id": "slack-bold-conversion",
"category": "scar",
"expect": "parity",
"input": "**important** word",
"native_output": "**important** word"
},
{
"id": "slack-link-conversion",
"category": "scar",
"expect": "parity",
"input": "[click here](https://example.com)",
"native_output": "[click here](https://example.com)"
},
{
"id": "slack-broadcast-mention",
"category": "scar",
"expect": "parity",
"input": "Hey <!everyone> and <!channel> and <!here>!",
"native_output": "Hey <!everyone> and <!channel> and <!here>!"
},
{
"id": "fence-lang-tag-slack",
"category": "scar",
"expect": "parity",
"input": "```text\nliteral first line issue\n```",
"native_output": "```text\nliteral first line issue\n```"
},
{
"id": "backslash-in-code",
"category": "scar",
"expect": "parity",
"input": "`C:\\Users\\ben\\file.txt` and ```\npath = \"a\\\\b\"\n```",
"native_output": "`C:\\Users\\ben\\file.txt` and ```\npath = \"a\\\\b\"\n```"
},
{
"id": "backtick-in-fence",
"category": "scar",
"expect": "parity",
"input": "```\nuse `inline` inside fence\n```",
"native_output": "```\nuse `inline` inside fence\n```"
},
{
"id": "header-with-bold",
"category": "scar",
"expect": "parity",
"input": "## The **Real** Deal",
"native_output": "## The **Real** Deal"
},
{
"id": "table-cjk",
"category": "scar",
"expect": "divergent",
"input": "| 名前 | 値 |\n|------|----|\n| 中文 | 42 |\n| b | 2 |",
"native_output": "**中文**\n• 値: 42\n\n**b**\n• 値: 2",
"note": "same as table-simple"
},
{
"id": "link-display-escapes",
"category": "scar",
"expect": "parity",
"input": "[v2.0 (beta)](https://example.com/v2)",
"native_output": "[v2.0 (beta)](https://example.com/v2)"
},
{
"id": "media-tag",
"category": "adversarial",
"expect": "parity",
"input": "Here you go\nMEDIA:/tmp/output.png\ndone",
"native_output": "Here you go\nMEDIA:/tmp/output.png\ndone"
},
{
"id": "unclosed-fence",
"category": "adversarial",
"expect": "parity",
"input": "```python\nprint('never closed')",
"native_output": "```python\nprint('never closed')"
},
{
"id": "pathological-nesting",
"category": "adversarial",
"expect": "parity",
"input": "**bold *italic ~~struck `code` struck~~ italic* bold**",
"native_output": "**bold *italic ~~struck `code` struck~~ italic* bold**"
},
{
"id": "placeholder-injection",
"category": "adversarial",
"expect": "parity",
"input": "sneaky \u0000PH0\u0000 token and \u0000SL1\u0000 too",
"native_output": "sneaky \u0000PH0\u0000 token and \u0000SL1\u0000 too"
},
{
"id": "triple-markers",
"category": "adversarial",
"expect": "parity",
"input": "***what is this*** and ____that____",
"native_output": "***what is this*** and ____that____"
},
{
"id": "empty-string",
"category": "adversarial",
"expect": "parity",
"input": "",
"native_output": ""
},
{
"id": "whitespace-only",
"category": "adversarial",
"expect": "parity",
"input": " \n\t\n ",
"native_output": " \n\t\n "
},
{
"id": "long-line",
"category": "adversarial",
"expect": "parity",
"input": "word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word ",
"native_output": "word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word "
},
{
"id": "many-fences",
"category": "adversarial",
"expect": "parity",
"input": "```\na\n```\nmid\n```\nb\n```\nend ```inline``` tail",
"native_output": "```\na\n```\nmid\n```\nb\n```\nend ```inline``` tail"
}
]
}
+322
View File
@@ -0,0 +1,322 @@
{
"$comment": "GENERATED — do not hand-edit. Regenerate with hermes-agent scripts/generate_conformance_vectors.py; the native renderers are the oracle (executable spec).",
"oracle": {
"repo": "NousResearch/hermes-agent",
"commit": "40eebc7d70f3d8e95c429c8aa482f31ba6c867f6",
"generator": "scripts/generate_conformance_vectors.py",
"generator_version": 1
},
"platform": "slack",
"vectors": [
{
"id": "plain-text",
"category": "grid",
"expect": "parity",
"input": "Just a plain sentence.",
"native_output": "Just a plain sentence."
},
{
"id": "bold",
"category": "grid",
"expect": "parity",
"input": "This is **bold** text.",
"native_output": "This is *bold* text."
},
{
"id": "italic",
"category": "grid",
"expect": "parity",
"input": "This is *italic* text.",
"native_output": "This is _italic_ text."
},
{
"id": "bold-italic",
"category": "grid",
"expect": "parity",
"input": "Mix of **bold** and *italic* in one line.",
"native_output": "Mix of *bold* and _italic_ in one line."
},
{
"id": "strikethrough",
"category": "grid",
"expect": "parity",
"input": "This is ~~struck~~ text.",
"native_output": "This is ~struck~ text."
},
{
"id": "inline-code",
"category": "grid",
"expect": "parity",
"input": "Run `pip install hermes` to start.",
"native_output": "Run `pip install hermes` to start."
},
{
"id": "fenced-code",
"category": "grid",
"expect": "parity",
"input": "```\nprint('hello')\n```",
"native_output": "```\nprint('hello')\n```"
},
{
"id": "fenced-code-lang",
"category": "grid",
"expect": "parity",
"input": "```python\ndef f(x):\n return x * 2\n```",
"native_output": "```\ndef f(x):\n return x * 2\n```"
},
{
"id": "link",
"category": "grid",
"expect": "parity",
"input": "See [the docs](https://example.com/docs) for more.",
"native_output": "See <https://example.com/docs|the docs> for more."
},
{
"id": "link-parens-url",
"category": "grid",
"expect": "parity",
"input": "See [spec](https://example.com/a_(b)) here.",
"native_output": "See <https://example.com/a_(b)|spec> here."
},
{
"id": "header-h1",
"category": "grid",
"expect": "parity",
"input": "# Big Title\nBody follows.",
"native_output": "*Big Title*\nBody follows."
},
{
"id": "header-h2",
"category": "grid",
"expect": "parity",
"input": "## Section\nBody follows.",
"native_output": "*Section*\nBody follows."
},
{
"id": "header-h3",
"category": "grid",
"expect": "parity",
"input": "### Sub-section\nBody follows.",
"native_output": "*Sub-section*\nBody follows."
},
{
"id": "ul-list",
"category": "grid",
"expect": "parity",
"input": "- first\n- second\n- third",
"native_output": "- first\n- second\n- third"
},
{
"id": "ol-list",
"category": "grid",
"expect": "parity",
"input": "1. first\n2. second\n3. third",
"native_output": "1. first\n2. second\n3. third"
},
{
"id": "nested-list",
"category": "grid",
"expect": "parity",
"input": "- outer\n - inner one\n - inner two\n- outer two",
"native_output": "- outer\n - inner one\n - inner two\n- outer two"
},
{
"id": "blockquote",
"category": "grid",
"expect": "parity",
"input": "> quoted wisdom\nregular line",
"native_output": "> quoted wisdom\nregular line"
},
{
"id": "hrule",
"category": "grid",
"expect": "parity",
"input": "above\n\n---\n\nbelow",
"native_output": "above\n\n---\n\nbelow"
},
{
"id": "table-simple",
"category": "grid",
"expect": "parity",
"input": "| name | value |\n|------|-------|\n| a | 1 |\n| b | 2 |",
"native_output": "```\n| name | value |\n| ---- | ----- |\n| a | 1 |\n| b | 2 |\n```"
},
{
"id": "emoji",
"category": "grid",
"expect": "parity",
"input": "Done ✅ with 🎉 emoji 👀 test.",
"native_output": "Done ✅ with 🎉 emoji 👀 test."
},
{
"id": "cjk",
"category": "grid",
"expect": "parity",
"input": "中文测试:**粗体** 和 `代码` 混排。",
"native_output": "中文测试:*粗体* 和 `代码` 混排。"
},
{
"id": "bare-url",
"category": "grid",
"expect": "parity",
"input": "Visit https://example.com/path?q=1&r=2 today.",
"native_output": "Visit https://example.com/path?q=1&amp;r=2 today."
},
{
"id": "mixed-document",
"category": "grid",
"expect": "parity",
"input": "## Report\n\nStatus: **green**. Details in `runbook.md`.\n\n- item *one*\n- item **two**\n\n```sh\nmake deploy\n```\n\nSee [dashboard](https://grafana.example.com/d/x).",
"native_output": "*Report*\n\nStatus: *green*. Details in `runbook.md`.\n\n- item _one_\n- item *two*\n\n```\nmake deploy\n```\n\nSee <https://grafana.example.com/d/x|dashboard>."
},
{
"id": "mdv2-reserved-chars",
"category": "scar",
"expect": "parity",
"input": "Price is 3.50 (was 4.00) — save ~12%! #deal +tax = win.",
"native_output": "Price is 3.50 (was 4.00) — save ~12%! #deal +tax = win."
},
{
"id": "mdv2-underscores",
"category": "scar",
"expect": "parity",
"input": "snake_case_name and file_name.py in prose.",
"native_output": "snake_case_name and file_name.py in prose."
},
{
"id": "mdv2-brackets",
"category": "scar",
"expect": "parity",
"input": "Array[0] and dict{key} and (parens) live here.",
"native_output": "Array[0] and dict{key} and (parens) live here."
},
{
"id": "slack-bold-conversion",
"category": "scar",
"expect": "parity",
"input": "**important** word",
"native_output": "*important* word"
},
{
"id": "slack-link-conversion",
"category": "scar",
"expect": "parity",
"input": "[click here](https://example.com)",
"native_output": "<https://example.com|click here>"
},
{
"id": "slack-broadcast-mention",
"category": "scar",
"expect": "parity",
"input": "Hey <!everyone> and <!channel> and <!here>!",
"native_output": "Hey &lt;!everyone&gt; and &lt;!channel&gt; and &lt;!here&gt;!"
},
{
"id": "fence-lang-tag-slack",
"category": "scar",
"expect": "parity",
"input": "```text\nliteral first line issue\n```",
"native_output": "```\nliteral first line issue\n```"
},
{
"id": "backslash-in-code",
"category": "scar",
"expect": "parity",
"input": "`C:\\Users\\ben\\file.txt` and ```\npath = \"a\\\\b\"\n```",
"native_output": "`C:\\Users\\ben\\file.txt` and ```\npath = \"a\\\\b\"\n```"
},
{
"id": "backtick-in-fence",
"category": "scar",
"expect": "parity",
"input": "```\nuse `inline` inside fence\n```",
"native_output": "```\nuse `inline` inside fence\n```"
},
{
"id": "header-with-bold",
"category": "scar",
"expect": "parity",
"input": "## The **Real** Deal",
"native_output": "*The Real Deal*"
},
{
"id": "table-cjk",
"category": "scar",
"expect": "parity",
"input": "| 名前 | 値 |\n|------|----|\n| 中文 | 42 |\n| b | 2 |",
"native_output": "```\n| 名前 | 値 |\n| ---- | --- |\n| 中文 | 42 |\n| b | 2 |\n```"
},
{
"id": "link-display-escapes",
"category": "scar",
"expect": "parity",
"input": "[v2.0 (beta)](https://example.com/v2)",
"native_output": "<https://example.com/v2|v2.0 (beta)>"
},
{
"id": "media-tag",
"category": "adversarial",
"expect": "parity",
"input": "Here you go\nMEDIA:/tmp/output.png\ndone",
"native_output": "Here you go\nMEDIA:/tmp/output.png\ndone"
},
{
"id": "unclosed-fence",
"category": "adversarial",
"expect": "divergent",
"input": "```python\nprint('never closed')",
"native_output": "```python\nprint('never closed')",
"note": "unterminated fence handling differs; both degrade without dropping content"
},
{
"id": "pathological-nesting",
"category": "adversarial",
"expect": "parity",
"input": "**bold *italic ~~struck `code` struck~~ italic* bold**",
"native_output": "*bold *italic ~~struck `code` struck~~ italic* bold*"
},
{
"id": "placeholder-injection",
"category": "adversarial",
"expect": "divergent",
"input": "sneaky \u0000PH0\u0000 token and \u0000SL1\u0000 too",
"native_output": "sneaky \u0000PH0\u0000 token and \u0000SL1\u0000 too",
"note": "\\x00SL tokens are the native renderer's own placeholder alphabet; connector uses a different scheme"
},
{
"id": "triple-markers",
"category": "adversarial",
"expect": "parity",
"input": "***what is this*** and ____that____",
"native_output": "*_what is this_* and ____that____"
},
{
"id": "empty-string",
"category": "adversarial",
"expect": "parity",
"input": "",
"native_output": ""
},
{
"id": "whitespace-only",
"category": "adversarial",
"expect": "parity",
"input": " \n\t\n ",
"native_output": " \n\t\n "
},
{
"id": "long-line",
"category": "adversarial",
"expect": "parity",
"input": "word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word ",
"native_output": "word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word "
},
{
"id": "many-fences",
"category": "adversarial",
"expect": "parity",
"input": "```\na\n```\nmid\n```\nb\n```\nend ```inline``` tail",
"native_output": "```\na\n```\nmid\n```\nb\n```\nend ```inline``` tail"
}
]
}
+325
View File
@@ -0,0 +1,325 @@
{
"$comment": "GENERATED — do not hand-edit. Regenerate with hermes-agent scripts/generate_conformance_vectors.py; the native renderers are the oracle (executable spec).",
"oracle": {
"repo": "NousResearch/hermes-agent",
"commit": "40eebc7d70f3d8e95c429c8aa482f31ba6c867f6",
"generator": "scripts/generate_conformance_vectors.py",
"generator_version": 1
},
"platform": "telegram",
"vectors": [
{
"id": "plain-text",
"category": "grid",
"expect": "semantic",
"input": "Just a plain sentence.",
"native_output": "Just a plain sentence\\."
},
{
"id": "bold",
"category": "grid",
"expect": "semantic",
"input": "This is **bold** text.",
"native_output": "This is *bold* text\\."
},
{
"id": "italic",
"category": "grid",
"expect": "semantic",
"input": "This is *italic* text.",
"native_output": "This is _italic_ text\\."
},
{
"id": "bold-italic",
"category": "grid",
"expect": "semantic",
"input": "Mix of **bold** and *italic* in one line.",
"native_output": "Mix of *bold* and _italic_ in one line\\."
},
{
"id": "strikethrough",
"category": "grid",
"expect": "semantic",
"input": "This is ~~struck~~ text.",
"native_output": "This is ~struck~ text\\."
},
{
"id": "inline-code",
"category": "grid",
"expect": "semantic",
"input": "Run `pip install hermes` to start.",
"native_output": "Run `pip install hermes` to start\\."
},
{
"id": "fenced-code",
"category": "grid",
"expect": "semantic",
"input": "```\nprint('hello')\n```",
"native_output": "```\nprint('hello')\n```"
},
{
"id": "fenced-code-lang",
"category": "grid",
"expect": "semantic",
"input": "```python\ndef f(x):\n return x * 2\n```",
"native_output": "```python\ndef f(x):\n return x * 2\n```"
},
{
"id": "link",
"category": "grid",
"expect": "semantic",
"input": "See [the docs](https://example.com/docs) for more.",
"native_output": "See [the docs](https://example.com/docs) for more\\."
},
{
"id": "link-parens-url",
"category": "grid",
"expect": "semantic",
"input": "See [spec](https://example.com/a_(b)) here.",
"native_output": "See [spec](https://example.com/a_\\(b\\)) here\\."
},
{
"id": "header-h1",
"category": "grid",
"expect": "semantic",
"input": "# Big Title\nBody follows.",
"native_output": "*Big Title*\nBody follows\\."
},
{
"id": "header-h2",
"category": "grid",
"expect": "semantic",
"input": "## Section\nBody follows.",
"native_output": "*Section*\nBody follows\\."
},
{
"id": "header-h3",
"category": "grid",
"expect": "semantic",
"input": "### Sub-section\nBody follows.",
"native_output": "*Sub\\-section*\nBody follows\\."
},
{
"id": "ul-list",
"category": "grid",
"expect": "semantic",
"input": "- first\n- second\n- third",
"native_output": "\\- first\n\\- second\n\\- third"
},
{
"id": "ol-list",
"category": "grid",
"expect": "semantic",
"input": "1. first\n2. second\n3. third",
"native_output": "1\\. first\n2\\. second\n3\\. third"
},
{
"id": "nested-list",
"category": "grid",
"expect": "semantic",
"input": "- outer\n - inner one\n - inner two\n- outer two",
"native_output": "\\- outer\n \\- inner one\n \\- inner two\n\\- outer two"
},
{
"id": "blockquote",
"category": "grid",
"expect": "semantic",
"input": "> quoted wisdom\nregular line",
"native_output": "> quoted wisdom\nregular line"
},
{
"id": "hrule",
"category": "grid",
"expect": "semantic",
"input": "above\n\n---\n\nbelow",
"native_output": "above\n\n\\-\\-\\-\n\nbelow"
},
{
"id": "table-simple",
"category": "grid",
"expect": "divergent",
"input": "| name | value |\n|------|-------|\n| a | 1 |\n| b | 2 |",
"native_output": "*a*\n• value: 1\n\n*b*\n• value: 2",
"note": "native wraps tables into row groups; connector renders <pre> — content preserved, layout differs"
},
{
"id": "emoji",
"category": "grid",
"expect": "semantic",
"input": "Done ✅ with 🎉 emoji 👀 test.",
"native_output": "Done ✅ with 🎉 emoji 👀 test\\."
},
{
"id": "cjk",
"category": "grid",
"expect": "semantic",
"input": "中文测试:**粗体** 和 `代码` 混排。",
"native_output": "中文测试:*粗体* 和 `代码` 混排。"
},
{
"id": "bare-url",
"category": "grid",
"expect": "semantic",
"input": "Visit https://example.com/path?q=1&r=2 today.",
"native_output": "Visit https://example\\.com/path?q\\=1&r\\=2 today\\."
},
{
"id": "mixed-document",
"category": "grid",
"expect": "semantic",
"input": "## Report\n\nStatus: **green**. Details in `runbook.md`.\n\n- item *one*\n- item **two**\n\n```sh\nmake deploy\n```\n\nSee [dashboard](https://grafana.example.com/d/x).",
"native_output": "*Report*\n\nStatus: *green*\\. Details in `runbook.md`\\.\n\n\\- item _one_\n\\- item *two*\n\n```sh\nmake deploy\n```\n\nSee [dashboard](https://grafana.example.com/d/x)\\."
},
{
"id": "mdv2-reserved-chars",
"category": "scar",
"expect": "semantic",
"input": "Price is 3.50 (was 4.00) — save ~12%! #deal +tax = win.",
"native_output": "Price is 3\\.50 \\(was 4\\.00\\) — save \\~12%\\! \\#deal \\+tax \\= win\\."
},
{
"id": "mdv2-underscores",
"category": "scar",
"expect": "semantic",
"input": "snake_case_name and file_name.py in prose.",
"native_output": "snake\\_case\\_name and file\\_name\\.py in prose\\."
},
{
"id": "mdv2-brackets",
"category": "scar",
"expect": "semantic",
"input": "Array[0] and dict{key} and (parens) live here.",
"native_output": "Array\\[0\\] and dict\\{key\\} and \\(parens\\) live here\\."
},
{
"id": "slack-bold-conversion",
"category": "scar",
"expect": "semantic",
"input": "**important** word",
"native_output": "*important* word"
},
{
"id": "slack-link-conversion",
"category": "scar",
"expect": "semantic",
"input": "[click here](https://example.com)",
"native_output": "[click here](https://example.com)"
},
{
"id": "slack-broadcast-mention",
"category": "scar",
"expect": "semantic",
"input": "Hey <!everyone> and <!channel> and <!here>!",
"native_output": "Hey <\\!everyone\\> and <\\!channel\\> and <\\!here\\>\\!"
},
{
"id": "fence-lang-tag-slack",
"category": "scar",
"expect": "semantic",
"input": "```text\nliteral first line issue\n```",
"native_output": "```text\nliteral first line issue\n```"
},
{
"id": "backslash-in-code",
"category": "scar",
"expect": "semantic",
"input": "`C:\\Users\\ben\\file.txt` and ```\npath = \"a\\\\b\"\n```",
"native_output": "`C:\\\\Users\\\\ben\\\\file.txt` and ```\npath = \"a\\\\\\\\b\"\n```"
},
{
"id": "backtick-in-fence",
"category": "scar",
"expect": "semantic",
"input": "```\nuse `inline` inside fence\n```",
"native_output": "```\nuse \\`inline\\` inside fence\n```"
},
{
"id": "header-with-bold",
"category": "scar",
"expect": "semantic",
"input": "## The **Real** Deal",
"native_output": "*The Real Deal*"
},
{
"id": "table-cjk",
"category": "scar",
"expect": "divergent",
"input": "| 名前 | 値 |\n|------|----|\n| 中文 | 42 |\n| b | 2 |",
"native_output": "*中文*\n• 値: 42\n\n*b*\n• 値: 2",
"note": "same as table-simple (CJK width alignment is native-only)"
},
{
"id": "link-display-escapes",
"category": "scar",
"expect": "semantic",
"input": "[v2.0 (beta)](https://example.com/v2)",
"native_output": "[v2\\.0 \\(beta\\)](https://example.com/v2)"
},
{
"id": "media-tag",
"category": "adversarial",
"expect": "semantic",
"input": "Here you go\nMEDIA:/tmp/output.png\ndone",
"native_output": "Here you go\nMEDIA:/tmp/output\\.png\ndone"
},
{
"id": "unclosed-fence",
"category": "adversarial",
"expect": "divergent",
"input": "```python\nprint('never closed')",
"native_output": "\\`\\`\\`python\nprint\\('never closed'\\)",
"note": "unterminated fence: native escapes as prose, connector HTML may close the block — degraded either way, never a 400"
},
{
"id": "pathological-nesting",
"category": "adversarial",
"expect": "semantic",
"input": "**bold *italic ~~struck `code` struck~~ italic* bold**",
"native_output": "*bold \\*italic \\~\\~struck `code` struck\\~\\~ italic\\* bold*"
},
{
"id": "placeholder-injection",
"category": "adversarial",
"expect": "divergent",
"input": "sneaky \u0000PH0\u0000 token and \u0000SL1\u0000 too",
"native_output": "sneaky \u0000PH0\u0000 token and \u0000SL1\u0000 too",
"note": "NUL placeholder tokens are renderer-internal; each side neutralizes its own pattern"
},
{
"id": "triple-markers",
"category": "adversarial",
"expect": "semantic",
"input": "***what is this*** and ____that____",
"native_output": "*\\*what is this*\\* and \\_\\_\\_\\_that\\_\\_\\_\\_"
},
{
"id": "empty-string",
"category": "adversarial",
"expect": "semantic",
"input": "",
"native_output": ""
},
{
"id": "whitespace-only",
"category": "adversarial",
"expect": "divergent",
"input": " \n\t\n ",
"native_output": " \n\t\n ",
"note": "native collapses to empty-ish prose, connector HTML preserves — cosmetic"
},
{
"id": "long-line",
"category": "adversarial",
"expect": "semantic",
"input": "word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word ",
"native_output": "word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word "
},
{
"id": "many-fences",
"category": "adversarial",
"expect": "semantic",
"input": "```\na\n```\nmid\n```\nb\n```\nend ```inline``` tail",
"native_output": "```\na\n```\nmid\n```\nb\n```\nend ```inline``` tail"
}
]
}
+322
View File
@@ -0,0 +1,322 @@
{
"$comment": "GENERATED — do not hand-edit. Regenerate with hermes-agent scripts/generate_conformance_vectors.py; the native renderers are the oracle (executable spec).",
"oracle": {
"repo": "NousResearch/hermes-agent",
"commit": "40eebc7d70f3d8e95c429c8aa482f31ba6c867f6",
"generator": "scripts/generate_conformance_vectors.py",
"generator_version": 1
},
"platform": "whatsapp",
"vectors": [
{
"id": "plain-text",
"category": "grid",
"expect": "parity",
"input": "Just a plain sentence.",
"native_output": "Just a plain sentence."
},
{
"id": "bold",
"category": "grid",
"expect": "parity",
"input": "This is **bold** text.",
"native_output": "This is *bold* text."
},
{
"id": "italic",
"category": "grid",
"expect": "parity",
"input": "This is *italic* text.",
"native_output": "This is _italic_ text."
},
{
"id": "bold-italic",
"category": "grid",
"expect": "parity",
"input": "Mix of **bold** and *italic* in one line.",
"native_output": "Mix of *bold* and _italic_ in one line."
},
{
"id": "strikethrough",
"category": "grid",
"expect": "parity",
"input": "This is ~~struck~~ text.",
"native_output": "This is ~struck~ text."
},
{
"id": "inline-code",
"category": "grid",
"expect": "parity",
"input": "Run `pip install hermes` to start.",
"native_output": "Run `pip install hermes` to start."
},
{
"id": "fenced-code",
"category": "grid",
"expect": "parity",
"input": "```\nprint('hello')\n```",
"native_output": "```\nprint('hello')\n```"
},
{
"id": "fenced-code-lang",
"category": "grid",
"expect": "parity",
"input": "```python\ndef f(x):\n return x * 2\n```",
"native_output": "```python\ndef f(x):\n return x * 2\n```"
},
{
"id": "link",
"category": "grid",
"expect": "parity",
"input": "See [the docs](https://example.com/docs) for more.",
"native_output": "See the docs (https://example.com/docs) for more."
},
{
"id": "link-parens-url",
"category": "grid",
"expect": "parity",
"input": "See [spec](https://example.com/a_(b)) here.",
"native_output": "See spec (https://example.com/a_(b)) here."
},
{
"id": "header-h1",
"category": "grid",
"expect": "parity",
"input": "# Big Title\nBody follows.",
"native_output": "*Big Title*\nBody follows."
},
{
"id": "header-h2",
"category": "grid",
"expect": "parity",
"input": "## Section\nBody follows.",
"native_output": "*Section*\nBody follows."
},
{
"id": "header-h3",
"category": "grid",
"expect": "parity",
"input": "### Sub-section\nBody follows.",
"native_output": "*Sub-section*\nBody follows."
},
{
"id": "ul-list",
"category": "grid",
"expect": "parity",
"input": "- first\n- second\n- third",
"native_output": "- first\n- second\n- third"
},
{
"id": "ol-list",
"category": "grid",
"expect": "parity",
"input": "1. first\n2. second\n3. third",
"native_output": "1. first\n2. second\n3. third"
},
{
"id": "nested-list",
"category": "grid",
"expect": "parity",
"input": "- outer\n - inner one\n - inner two\n- outer two",
"native_output": "- outer\n - inner one\n - inner two\n- outer two"
},
{
"id": "blockquote",
"category": "grid",
"expect": "parity",
"input": "> quoted wisdom\nregular line",
"native_output": "> quoted wisdom\nregular line"
},
{
"id": "hrule",
"category": "grid",
"expect": "parity",
"input": "above\n\n---\n\nbelow",
"native_output": "above\n\n---\n\nbelow"
},
{
"id": "table-simple",
"category": "grid",
"expect": "parity",
"input": "| name | value |\n|------|-------|\n| a | 1 |\n| b | 2 |",
"native_output": "| name | value |\n|------|-------|\n| a | 1 |\n| b | 2 |"
},
{
"id": "emoji",
"category": "grid",
"expect": "parity",
"input": "Done ✅ with 🎉 emoji 👀 test.",
"native_output": "Done ✅ with 🎉 emoji 👀 test."
},
{
"id": "cjk",
"category": "grid",
"expect": "parity",
"input": "中文测试:**粗体** 和 `代码` 混排。",
"native_output": "中文测试:*粗体* 和 `代码` 混排。"
},
{
"id": "bare-url",
"category": "grid",
"expect": "parity",
"input": "Visit https://example.com/path?q=1&r=2 today.",
"native_output": "Visit https://example.com/path?q=1&r=2 today."
},
{
"id": "mixed-document",
"category": "grid",
"expect": "parity",
"input": "## Report\n\nStatus: **green**. Details in `runbook.md`.\n\n- item *one*\n- item **two**\n\n```sh\nmake deploy\n```\n\nSee [dashboard](https://grafana.example.com/d/x).",
"native_output": "*Report*\n\nStatus: *green*. Details in `runbook.md`.\n\n- item _one_\n- item *two*\n\n```sh\nmake deploy\n```\n\nSee dashboard (https://grafana.example.com/d/x)."
},
{
"id": "mdv2-reserved-chars",
"category": "scar",
"expect": "parity",
"input": "Price is 3.50 (was 4.00) — save ~12%! #deal +tax = win.",
"native_output": "Price is 3.50 (was 4.00) — save ~12%! #deal +tax = win."
},
{
"id": "mdv2-underscores",
"category": "scar",
"expect": "parity",
"input": "snake_case_name and file_name.py in prose.",
"native_output": "snake_case_name and file_name.py in prose."
},
{
"id": "mdv2-brackets",
"category": "scar",
"expect": "parity",
"input": "Array[0] and dict{key} and (parens) live here.",
"native_output": "Array[0] and dict{key} and (parens) live here."
},
{
"id": "slack-bold-conversion",
"category": "scar",
"expect": "parity",
"input": "**important** word",
"native_output": "*important* word"
},
{
"id": "slack-link-conversion",
"category": "scar",
"expect": "parity",
"input": "[click here](https://example.com)",
"native_output": "click here (https://example.com)"
},
{
"id": "slack-broadcast-mention",
"category": "scar",
"expect": "parity",
"input": "Hey <!everyone> and <!channel> and <!here>!",
"native_output": "Hey <!everyone> and <!channel> and <!here>!"
},
{
"id": "fence-lang-tag-slack",
"category": "scar",
"expect": "parity",
"input": "```text\nliteral first line issue\n```",
"native_output": "```text\nliteral first line issue\n```"
},
{
"id": "backslash-in-code",
"category": "scar",
"expect": "parity",
"input": "`C:\\Users\\ben\\file.txt` and ```\npath = \"a\\\\b\"\n```",
"native_output": "`C:\\Users\\ben\\file.txt` and ```\npath = \"a\\\\b\"\n```"
},
{
"id": "backtick-in-fence",
"category": "scar",
"expect": "parity",
"input": "```\nuse `inline` inside fence\n```",
"native_output": "```\nuse `inline` inside fence\n```"
},
{
"id": "header-with-bold",
"category": "scar",
"expect": "parity",
"input": "## The **Real** Deal",
"native_output": "*The *Real* Deal*"
},
{
"id": "table-cjk",
"category": "scar",
"expect": "parity",
"input": "| 名前 | 値 |\n|------|----|\n| 中文 | 42 |\n| b | 2 |",
"native_output": "| 名前 | 値 |\n|------|----|\n| 中文 | 42 |\n| b | 2 |"
},
{
"id": "link-display-escapes",
"category": "scar",
"expect": "parity",
"input": "[v2.0 (beta)](https://example.com/v2)",
"native_output": "v2.0 (beta) (https://example.com/v2)"
},
{
"id": "media-tag",
"category": "adversarial",
"expect": "parity",
"input": "Here you go\nMEDIA:/tmp/output.png\ndone",
"native_output": "Here you go\nMEDIA:/tmp/output.png\ndone"
},
{
"id": "unclosed-fence",
"category": "adversarial",
"expect": "divergent",
"input": "```python\nprint('never closed')",
"native_output": "```python\nprint('never closed')",
"note": "unterminated fence handling differs; both degrade without dropping content"
},
{
"id": "pathological-nesting",
"category": "adversarial",
"expect": "parity",
"input": "**bold *italic ~~struck `code` struck~~ italic* bold**",
"native_output": "*bold _italic ~struck `code` struck~ italic_ bold*"
},
{
"id": "placeholder-injection",
"category": "adversarial",
"expect": "divergent",
"input": "sneaky \u0000PH0\u0000 token and \u0000SL1\u0000 too",
"native_output": "sneaky \u0000PH0\u0000 token and \u0000SL1\u0000 too",
"note": "placeholder alphabets are renderer-internal"
},
{
"id": "triple-markers",
"category": "adversarial",
"expect": "parity",
"input": "***what is this*** and ____that____",
"native_output": "**what is this** and *__that*__"
},
{
"id": "empty-string",
"category": "adversarial",
"expect": "parity",
"input": "",
"native_output": ""
},
{
"id": "whitespace-only",
"category": "adversarial",
"expect": "parity",
"input": " \n\t\n ",
"native_output": " \n\t\n "
},
{
"id": "long-line",
"category": "adversarial",
"expect": "parity",
"input": "word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word ",
"native_output": "word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word "
},
{
"id": "many-fences",
"category": "adversarial",
"expect": "parity",
"input": "```\na\n```\nmid\n```\nb\n```\nend ```inline``` tail",
"native_output": "```\na\n```\nmid\n```\nb\n```\nend ```inline``` tail"
}
]
}