Skip to content

fix(docs): sanitize emoji shortcodes in generated SDK docs - #780

Merged
christineschen merged 6 commits into
mainfrom
devin/1786394635-fix-docs-emoji-shortcodes
Oct 6, 2026
Merged

christineschen merged 6 commits into
mainfrom
devin/1786394635-fix-docs-emoji-shortcodes

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The Parameters tables on openrouter.ai/docs/client-sdks/typescript/** render :heavy_check_mark: as literal text. Speakeasy emits GitHub-flavored emoji shortcodes; GitHub expands them, Mintlify does not, and the docs site mounts this repo's docs/ tree directly through a sourceRef entry in openrouter-web's projects/docs/docs.json.

Editing the generated MDX alone would not hold, because the next speakeasy run rewrites it. So this PR pairs a one-time pass with a post-generation step:

  1. scripts/sanitize-docs-emoji.sh rewrites docs/**/*.mdx in place:

    :heavy_check_mark: -> ✅
    :heavy_minus_sign: -> ➖
    :warning:          -> ⚠️
    

    Scoped to docs/ only. Root README.md and the workflow YAML keep their shortcodes, which render correctly on GitHub and npm.

  2. The script runs immediately after speakeasy run and before gen-docs-nav.sh in speakeasy_run_on_pr.yaml, so spec-change PRs land sanitized.

  3. A new docs-nav.yaml mirrors the workflow python-sdk and go-sdk already have. This repo had no pull_request-triggered docs job, so the scheduled generation path in sdk_generation.yaml opens PRs that neither sanitize emoji nor regenerate navigation. The new workflow covers both on that path.

  4. docs-nav.yaml and speakeasy_run_on_pr.yaml share one concurrency group keyed on the PR number, with cancel-in-progress: false. Both end with int128/update-generated-files-action@v2 pushing to the PR head branch, and a Speakeasy regeneration PR touches both .speakeasy/in.openapi.yaml and docs/**, so without serialization the second push would be rejected as non-fast-forward.

  5. The one-time pass: 1,428 files, 6,933 shortcodes replaced (rebased onto main on 2026-10-03).

  6. scripts/sanitize-docs-emoji.sh ends with a residual guard: if any standalone :[a-z][a-z0-9_+-]*: token (not preceded or followed by a word character or :) survives the substitution, it prints the file and line and exits non-zero, so a new shortcode Speakeasy starts emitting fails at generation time instead of shipping as literal text. Zero matches remain today, so the guard passes on current output.

Verification

  • Zero shortcode matches remain under docs/; the six :warning: occurrences in workflow YAML are untouched.
  • Re-running the script produces no diff.

Durability, now confirmed

Speakeasy regeneration PR #784 landed on main while this PR was open. It ran PR Validation, a plain pull_request workflow, which establishes that pull_request workflows do fire on the bot-authored regeneration PRs, so the sanitize step will run on future generations. auto-merge-speakeasy-pr.yaml waits for checks to complete before merging, so the sanitize commit has a window to land, but the poll can observe a momentarily-empty pending set between commits. That race predates this change and applies equally to gen-docs-nav.sh.

Rebase (2026-10-03)

Reopened after Pylon #4403 reported the same bug from a customer. The vendor's suggested script only rewrites description fields in OpenAPI files, and the spec has no shortcodes in it, so it doesn't fix this. The shortcodes come from Speakeasy's docs templates.

  • Rebuilt on current main: same .github and scripts changes, then the one-time pass was re-run fresh instead of replaying the old generated-docs commits.

  • The residual guard now ignores URN-style colon runs. New OAuth docs on main contain urn:ietf:params:oauth:token-type:jwt, which the old pattern flagged as :params: etc.:

    - grep -HnE ':[a-z][a-z0-9_+-]*:'
    + grep -HnP '(?<![\w:]):[a-z][a-z0-9_+-]*:(?![\w:])'

Link to Devin session: https://openrouter.devinenterprise.com/sessions/1589ee9058c442958d427eac4e989f11
Open in Devin Desktop: https://openrouter.devinenterprise.com/desktop/session/1589ee9058c442958d427eac4e989f11?variant=devin

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author
Original prompt from jason.schrader

SYSTEM:
=== BEGIN THREAD HISTORY (in #gtm-agents) ===
<most_recent_message>
Jason Schrader (U0BLD9PFY30) [ts=1786394064.313869]: @Devin I found a few spots in our docs where emoji shortcodes are listed in text form and not displayed in tables, e.g. ✔️ renders as :heavy_check_mark: in the table instead of the actual icon. Let's identify the root cause then create a PR to get it all fixed up. From what I see, it's all under a table in the "Parameters" section of the different Client SDK files.
<https://openrouter.ai/docs/client-sdks/typescript/sdks/files/README|openrouter.ai/docs/…/README>
<https://openrouter.ai/docs/client-sdks/python/sdks/benchmarks/README|openrouter.ai/docs/…/README>
<https://openrouter.ai/docs/client-sdks/go/sdks/betaanalytics/README|openrouter.ai/docs/…/README>
</most_recent_message>
=== END THREAD HISTORY ===
Channel ID: C0AD8UNM761
Thread URL: https://openrouter.slack.com/archives/C0AD8UNM761/p1786394064313869?thread_ts=1786394064.313869&amp;cid=C0AD8UNM761

The latest message is the one right above that tagged you. The <most_recent_message> is the message that you should use to guide your goals + task for this session, and you should use the rest of the slack thread as context.
A [ts=...] marker on a Slack message is that message's timestamp. To act on a specific message with the slack tool (e.g. adding an emoji reaction via the reaction command), pass that value as timestamp along with the Channel ID — no extra lookup call is needed.

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@mintlify

mintlify Bot commented Aug 10, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-production 🟡 Building – Aug 10, 2026, 9:24 PM

@mintlify

mintlify Bot commented Aug 10, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-staging 🟡 Building – Aug 10, 2026, 9:24 PM

@mintlify

mintlify Bot commented Aug 10, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-production 🟡 Building – Aug 10, 2026, 9:24 PM

@mintlify

mintlify Bot commented Aug 10, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-staging 🟡 Building – Aug 10, 2026, 9:24 PM

@mintlify

mintlify Bot commented Aug 10, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-production 🟡 Building – Aug 10, 2026, 9:24 PM

@mintlify

mintlify Bot commented Aug 10, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-staging 🟡 Building – Aug 10, 2026, 9:24 PM

perry-the-pr-reviewer[bot]

This comment was marked as outdated.

@mintlify

mintlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-production 🟡 Building – Aug 11, 2026, 1:23 AM

@mintlify

mintlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-staging 🟡 Building – Aug 11, 2026, 1:23 AM

@mintlify

mintlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-production 🟡 Building – Aug 11, 2026, 3:26 AM

@mintlify

mintlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-staging 🟡 Building – Aug 11, 2026, 3:26 AM

@mintlify

mintlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-production 🟡 Building – Aug 11, 2026, 4:23 AM

@mintlify

mintlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-staging 🟡 Building – Aug 11, 2026, 4:23 AM

@mintlify

mintlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-production 🟡 Building – Aug 11, 2026, 4:23 AM

@mintlify

mintlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-staging 🟡 Building – Aug 11, 2026, 4:23 AM

@mintlify

mintlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-production 🟡 Building – Aug 11, 2026, 4:23 AM

@mintlify

mintlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
openrouter-staging 🟡 Building – Aug 11, 2026, 4:23 AM

perry-the-pr-reviewer[bot]

This comment was marked as outdated.

@jason-schrader-openrouter

Copy link
Copy Markdown

Closing in favor of coordination with our vendor

@devin-ai-integration devin-ai-integration Bot reopened this Oct 6, 2026
@devin-ai-integration
devin-ai-integration Bot force-pushed the devin/1786394635-fix-docs-emoji-shortcodes branch from 3173df0 to 08655a5 Compare October 6, 2026 16:04
@mintlify

mintlify Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
openrouter-production 🟢 Ready View Preview Oct 6, 2026, 6:15 PM

@mintlify

mintlify Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
openrouter-staging 🟢 Ready View Preview Oct 6, 2026, 6:17 PM

perry-the-pr-reviewer[bot]
perry-the-pr-reviewer Bot previously approved these changes Oct 6, 2026

@perry-the-pr-reviewer perry-the-pr-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probe-permission-check

@perry-the-pr-reviewer
perry-the-pr-reviewer Bot dismissed their stale review October 6, 2026 17:54

probe cleanup

@perry-the-pr-reviewer perry-the-pr-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perry's Review

Verdict: 💬 Comments / questions — the review is LGTM (both prior findings verified fixed; probe-tested, idempotent, CI green). Posted as a comment rather than an approval because the maintainer GitHub App on OpenRouterTeam currently lacks pull_requests:write, so the approval gate cannot carry the maintainer identity. A maintainer should re-approve once the permission is granted.
Risk: 🟢 Low

Findings, verification & risk assessment

Third-round review on ca54649. Both prior findings are verified fixed in the working tree, the sanitize script is correct and idempotent, and CI is green (gen-docs-nav SUCCESS, validate / validate SUCCESS).

Prior findings — resolved

  1. Concurrent workflow push race — docs-nav.yaml and speakeasy_run_on_pr.yaml now share concurrency: generated-files-${{ github.event.pull_request.number || github.ref }} with cancel-in-progress: false, so the two auto-committing workflows serialize instead of racing non-fast-forward pushes to the PR head branch.
  2. workflow_dispatch could auto-commit straight to main — fixed in ca54649: the auto-commit step is now gated with if: github.event_name == 'pull_request', so a manual dispatch runs sanitize + nav regeneration but never pushes to main.

What was verified this round

  • Sanitize script (scripts/sanitize-docs-emoji.sh): set -euo pipefail, repo-root resolution via BASH_SOURCE, docs/ existence check, scoped to docs/**/*.mdx only. Re-run against the branch's docs tree produces zero diff (idempotent). perl is preinstalled on GitHub-hosted runners.
  • Residual guard: grep -HnP '(?<![\w:]):[a-z][a-z0-9_+-]*:(?![\w:])' with || true so set -e doesn't abort on grep's no-match exit, [[ -n "$matches" ]] gating the error path, actionable stderr, exit 1. Probe-tested: an injected unmapped :sparkles: shortcode correctly fails the script; a URN-only line (urn:ietf:params:oauth:token-type:jwt) correctly passes — the lookbehind/lookahead fixed the false positive the earlier :params: match would have produced.
  • Sanitize ordering in speakeasy_run_on_pr.yaml is correct: after speakeasy run, before gen-docs-nav.sh.
  • README.md diff in this PR (the byok.list() → batch.list() example change) is part of the already-merged Speakeasy regeneration commits on the branch, not authored logic — those commits are ancestors of main.

Delta scope

The four PR-author commits (all Devin AI) are: the original sanitize pass, the URN-guard regex fix, the docs rewrite applying the replacements, and the dispatch auto-commit gate. The large src/ and tests/ churn in the file list belongs to the regenerated-spec commits already on main and is not part of this review's delta.

Estimated impact: worst case is a false-positive failure of the residual guard on a future generated-docs pattern that looks like a :word: shortcode — a one-line mapping or content fix in the docs generation workflow, with no runtime, data, or security surface affected.

Risk assessment & full factor table
Dimension Severity Risk Reasoning
Implementation risk 🟩 Low Script and workflow wiring are correct, idempotent, and probe-tested in review.
Premise risk 🟩 Low Post-generation sanitization is the right fix given Speakeasy rewrites the MDX on every run.
Estimated impact 🟩 Low Worst case is a contained CI failure in the docs pipeline, trivially correctable.
Risk Factor Severity Risk Reasoning
Reversibility 🟩 Low Revert restores the prior state; regeneration recreates output.
Detectability 🟩 Low The residual guard fails CI on any unmapped shortcode immediately.
Blast radius 🟩 Low Confined to the docs subtree mounted into the docs site.
Data integrity None No persisted state is touched.
Financial exposure None No billing surface.
Security and privacy exposure None No credential or auth path changed.
Propagation 🟩 Low Only the docs rendering pipeline consumes the output.
Availability None No serving path affected.
Recovery cost 🟩 Low A revert or one-line mapping fixes any issue.
Time to correct 🟩 Low Guard failures surface in the same workflow run.

Comment thread .github/workflows/docs-nav.yaml
Comment thread scripts/sanitize-docs-emoji.sh Outdated
…docs-emoji-shortcodes

# Conflicts:
#	docs/models/operations/createkeysdata.mdx
#	docs/models/operations/createkeysresponse.mdx
#	docs/models/operations/getkeydata.mdx
#	docs/models/operations/getkeyresponse.mdx
#	docs/models/operations/listdata.mdx
#	docs/models/operations/updatekeysdata.mdx
#	docs/models/operations/updatekeysresponse.mdx

@jason-schrader-openrouter jason-schrader-openrouter left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, that changelog size though 👀

all for emojis! 😆 🎉 🫶 💪 🥇

@christineschen
christineschen merged commit 6b71b2a into main Oct 6, 2026
2 checks passed
@christineschen
christineschen deleted the devin/1786394635-fix-docs-emoji-shortcodes branch October 6, 2026 18:54

This branch was successfully deployed

1 active deployment
staging - docs — 2a24ccb4 Deployed Oct 6, 2026 by mintlify[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants