Skip to content

feat(conformance): ingress mirror — pure parse cores + ingress vector generator - #72458

Open
benbarclay wants to merge 3 commits into
mainfrom
feat/relay-phase6-ingress-mirror
Open

feat(conformance): ingress mirror — pure parse cores + ingress vector generator#72458
benbarclay wants to merge 3 commits into
mainfrom
feat/relay-phase6-ingress-mirror

Conversation

@benbarclay

@benbarclay benbarclay commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Pure parse cores

Conformance oracle: ingress mirror — pure parse cores + vector generator (gateway side)

Gateway half of the ingress-mirror pair: NousResearch/gateway-gateway#181. Inbound twin of the egress generator (#71666, merged): synthetic platform payloads rendered through the native inbound PARSERS become the executable spec for the connector's normalizers.

The refactor (behavior-preserving, the enabler)

The native inbound parsers were not importable as pure functions — _build_message_event (~7.6k chars, 6 self-deps) and _build_message_event_from_cloud (~11k chars, media/dedupe/dispatch state). This PR extracts the payload-derivable half of each into pure cores; the adapters delegate:

Extraction honesty is machine-checked: oracle-fidelity tests drive the REAL adapter paths against the cores on every corpus payload (Telegram via PTB-style objects through the adapter shim; WhatsApp via the real _build_message_event_from_cloud with state stubbed) — if an adapter regains divergent inline logic, these fail.

scripts/generate_ingress_vectors.py

54 synthetic payloads (14 Telegram + 13 WhatsApp + 15 Discord + 12 Slack — every inbound scar rule has a named vector) → payload→expected-field JSON, oracle-SHA stamped, committed under tests/conformance/ingress_vectors/. UPDATE (second commit): Discord + Slack cores now included. The layer model made them tractable: discord_parse.py defines an SDK-view IR (DiscordMessageView, dual access — discord.py objects or raw-vocabulary dicts) over the ~18 fields layer 2 reads, with the pure rules (chat-type, <@id>/<@!id> mention stripping then command detection, forwarded-snapshot folding, referenced-attachment inheritance, voice-note vs audio classification, guild/forum thread naming); slack_parse.py extracts DM/MPIM classification (1:1 vs shared-surface), the #15421/#15464 thread_ts session-scoping invariants, mention detection, and bot-message classification. Adapters delegate at the clean seams; 3 new oracle-fidelity tests pin shim ≡ core. Corpus now 54 vectors across four platforms; 18 conformance tests.

tests/conformance/test_ingress_vectors.py (8 tests, three layers)

Generator invariants (determinism, shape, unique ids) · oracle fidelity (core ≡ adapter) · committed-vectors lockstep (regenerate-or-fail, the openapi.json discipline) · scar-rule coverage assertions.

Impact downstream

The connector runner found two real gg bugs on day one (Telegram reply-anchor thread leak #3206; WhatsApp button/list taps arriving as empty text) — fixed in the paired PR.

Tests

pytest tests/conformance/ 15 passed · test_whatsapp_cloud.py 113 · topics/gating suites 117 · tests/gateway/relay/ 266 — all green post-refactor. ruff + Windows-footguns clean.

… generator

The inbound half of the conformance oracle (egress landed in #71666):

- plugins/platforms/telegram/telegram_parse.py: PURE parse core extracted
  from TelegramAdapter._build_message_event — chat-type normalization,
  routable-thread rules (#3206 reply-anchor drop, #22423 General-topic
  '1'), reply context w/ native partial quotes (#22619), source identity.
  Dual access model: works on PTB objects AND raw Bot API dicts, so the
  generator needs no python-telegram-bot dependency. Adapter delegates
  (classmethod shim kept; reply-context inline logic replaced with a call;
  stateful fallbacks — rich echo, rich_sent_store — stay adapter-side).
- gateway/platforms/whatsapp_cloud_parse.py: PURE parse core extracted from
  WhatsAppCloudAdapter._build_message_event_from_cloud — type mapping,
  body extraction (button/list titles), reply context (id + is_own vs
  business number), media identification, group-shape discriminator.
  Adapter delegates for all payload-derivable fields.
- scripts/generate_ingress_vectors.py: renders 27 synthetic platform
  payloads (14 telegram + 13 whatsapp) through the cores and emits
  payload→expected-field JSON vectors, oracle-SHA stamped, committed under
  tests/conformance/ingress_vectors/.
- tests/conformance/test_ingress_vectors.py: 8 tests in three layers —
  generator invariants, ORACLE FIDELITY (core ≡ real adapter on every
  corpus payload: telegram via PTB-style objects against the adapter shim,
  whatsapp via the real _build_message_event_from_cloud with state stubbed),
  and committed-vectors lockstep.
- discord/slack ingress deferred: their native inbound paths are SDK
  event-object consumers; same extraction needed first (parity report).

Suites: conformance 15, whatsapp_cloud 113, topics/gating 117, relay 266 —
all green post-refactor (behavior-preserving).
@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on 2a7e4d9

ℹ️ Info

Desktop E2E visual evidence · View test artifacts · View job

1 visual diff.

inline evidence upload failed.

Failed to upload diff-665a0833239e-onboarding-overlay-diff.png with gh image (exit code 1): Error uploading /home/runner/work/_temp/e2e-evidence/diff-665a0833239e-onboarding-overlay-diff.png: step 0 (get upload token): uploadToken not found on repo page — do you have write access to NousResearch/hermes-agent? (or, if NousResearch enforces SAML SSO, authorize at https://github.com/orgs/NousResearch/sso)

@alt-glitch alt-glitch added type/test Test coverage or test infrastructure P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins platform/telegram Telegram bot adapter platform/whatsapp WhatsApp Business adapter labels Jul 27, 2026
…es + corpora

Completes the four-platform ingress mirror (telegram/whatsapp landed in the
prior commit). Layer model (documented in discord_parse.py): layer 1
(payload→SDK object — discord.py/Bolt) is the SDK-equivalence axiom, not
oracled; layer 2 (SDK-view → MessageEvent fields — the Hermes-unique
rules) is THE extracted, vectored spec; layer 3 (effects) stays adapter-side.

- plugins/platforms/discord/discord_parse.py: SDK-view IR
  (DiscordMessageView, dual access: discord.py objects OR raw-vocabulary
  dicts) + pure rules — chat-type classification, <@id>/<@!id> mention
  stripping (strip THEN command-detect), forwarded-snapshot folding,
  referenced-attachment inheritance, attachment→type classification
  (voice-note vs audio via is_voice_message/duration+waveform),
  guild/forum thread naming. Adapter delegates: _is_discord_voice_message_
  attachment, _format_thread_chat_name, and the _handle_message
  classification block.
- plugins/platforms/slack/slack_parse.py: DM/MPIM classification (1:1 vs
  shared-surface MPIM), thread_ts session scoping (#15421/#15464
  invariants incl. the thread_ts==ts root shape), mention detection,
  bot-message classification. Adapter delegates the DM-classification and
  channel-scoping blocks.
- scripts/generate_ingress_vectors.py: +15 discord + 12 slack vectors
  (54 total across four platforms).
- tests/conformance/test_ingress_vectors.py: +3 oracle-fidelity tests
  (adapter shim ≡ core on SDK-like objects) + scar-rule coverage; 18 total.

Suites: conformance 18; discord/slack gateway suites green (the only
failures in the -k 'discord or slack' sweep are pre-existing
order-dependent pollution — reproduce identically with this diff stashed).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have platform/telegram Telegram bot adapter platform/whatsapp WhatsApp Business adapter type/test Test coverage or test infrastructure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants