Push Channel Conformance Spec
Conformance tests for the Norq push notification compiler. The push compiler
takes Markdown input (with optional YAML frontmatter) and produces a
PushOutput with title, body, image, action_url, and platforms
fields.
Each example block specifies input markdown and one or more expected output
fragments (substrings that must appear in the compiled output).
Format:
- Opening fence: 32 backticks followed by
example channel=push - Input markdown (first section, before the first
.separator) .separator line- One or more expected fragments, each separated by
.lines - Closing fence: 32 backticks
The test runner serializes push output as <title>\n<body>. Fragments can
match either the title or body field.
Title Resolution
Push notifications have a single title string. The compiler resolves it from four sources in priority order:
:::headerdirective content (highest priority)- First Markdown heading (
# Heading) - Frontmatter
title:field - Empty string (when no source is found)
This priority order means :::header always wins over a heading, and a heading
always wins over frontmatter title:.
Priority 1: :::header directive
:::header content becomes the title. Any frontmatter title: field or
Markdown heading is ignored.
---
title: Ignored Title
---
:::header
New Message
:::
You have a new message.
.
New Message:::header with an expression in its content resolves the expression with the
current data. With null data, unresolvable paths produce empty strings, so the
static text portion is what the title contains.
:::header
Order Update
:::
Your package is ready for pickup.
.
Order UpdatePriority 2: First Markdown heading
When no :::header is present, the first heading (any level) becomes the
title. The heading text is excluded from the body.
# Account Alert
Your account needs attention.
.
Account AlertThe heading is skipped in the body because it was consumed as the title. Only the paragraph appears in the body.
# Package Delivered
Your package arrived at the door.
.
Package Delivered
.
Your package arrived at the door.Priority 3: Frontmatter title:
When neither :::header nor a heading is present, the frontmatter title:
field becomes the title.
---
title: Order Shipped
---
Your order is on its way.
.
Order ShippedPriority 4: Empty title
When no :::header, heading, or frontmatter title: is present, the title is
an empty string.
Just a body paragraph with no title source.
.
Just a body paragraph with no title source.Body Text
The body is plain text assembled from all content nodes except those consumed as the title source. Inline formatting markers (bold, italic) are stripped to plain text.
Paragraphs
Each paragraph contributes its text to the body. Consecutive paragraphs are
joined with \n.
Your package is on its way!
.
Your package is on its way!Multiple paragraphs
---
title: Notification
---
First line of info.
Second line of info.
.
First line of info.
.
Second line of info.Inline bold stripped
Inline formatting is stripped; only the plain text is kept.
Your order **#12345** has shipped.
.
Your order #12345 has shipped.Body truncated at 200 characters
The body is truncated to approximately 200 characters. If the text exceeds 200
characters, it is cut at the last space before the limit and ... is appended.
---
title: Long Notification
---
This is a very long body text that goes well beyond the two hundred character limit enforced by the push notification compiler so that it will definitely be truncated with an ellipsis at the end when compiled.
.
...Directives in Body
:::header excluded from body
:::header sets the title and is not included in the body.
:::header
Notification Title
:::
This is the body text.
.
This is the body text.:::footer excluded from body
:::footer is silently ignored in push output. Its content does not appear in
the title or body.
Your order is confirmed.
:::footer
You received this because you placed an order.
:::
.
Your order is confirmed.:::action excluded from body
:::action content sets action_url but does not contribute to the body
text. The link label and URL do not appear in the body.
Your package arrived.
:::action
[View Details](https://example.com/order/123)
:::
.
Your package arrived.:::highlight — star prefix in body
:::highlight content is prefixed with the ⭐ star emoji (U+2B50) and
included in the body.
:::highlight
Flash sale ends tonight
:::
.
⭐ Flash sale ends tonight:::callout — warning prefix in body
:::callout content is prefixed with the ⚠ warning emoji (U+26A0) and
included in the body.
:::callout
Your password expires in 3 days
:::
.
⚠ Your password expires in 3 daysLists in Body
Unordered list
Unordered list items are prefixed with - and joined with \n.
---
title: Order Summary
---
- Widget A
- Widget B
.
- Widget A
.
- Widget BOrdered list
Ordered list items are prefixed with N. (1-based).
---
title: Steps
---
1. Open the app
2. Tap notifications
.
1. Open the app
.
2. Tap notificationsEmoji Shortcodes
Emoji shortcodes are expanded in both the title and body. The title shortcodes
are expanded in the extract_title step; body shortcodes are expanded in
extract_body.
:::header
Launch :rocket:
:::
Deployment started.
.
Launch 🚀Hello :wave: welcome!
.
Hello 👋 welcome!Hero Image
:::hero sets the image field of PushOutput. The image field is not
included in the <title>\n<body> test runner output, so it is tested only via
unit tests in push.rs. The hero directive content does not appear in the
body.
Platform Frontmatter
The frontmatter keys ios, android, and web are extracted into the
platforms field of PushOutput. They do not appear in the body. Platform
configuration is tested via unit tests in push.rs.
Blockquote
Blockquote paragraph children are rendered as plain text in the body. The >
marker is not emitted.
---
title: Quote
---
> This is an important message.
.
This is an important message.