Skip to content

fix(shared): preserve code shielding and titled Markdown links - #30665

Open
ElliotDrel wants to merge 9 commits into
pingdotgg:fix/issue-30576from
ElliotDrel:fix/thread-link-markdown-shielding
Open

ElliotDrel wants to merge 9 commits into
pingdotgg:fix/issue-30576from
ElliotDrel:fix/thread-link-markdown-shielding

Conversation

@ElliotDrel

@ElliotDrel ElliotDrel commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

What Changed and Why

Issue: Follow-up to #30588 for #30576, targeting fix/issue-30576. Thread URLs inside CommonMark code could be rewritten, and mobile collected references then relabeled the same Markdown with two full scans/parses per render.

Why this change was necessary: Keep remark-parse's block/code correctness while avoiding repeated parsing for title updates. The existing bounded matcher still controls link acceptance, title exclusion and source offsets.

New status quo: prepareThreadLinks stores exact source and accepted link records, without retaining the AST or resolved titles. Reference collection, replacement and relabeling accept that result while preserving existing string callers. Mobile memoizes one current preparation on [markdown]; reference resolution uses the current environment and relabeling uses current titles. Changed source prepares again. No global cache, history, dependency, renderer refactor, provider or contract changes. Web/desktop composer string callers preserve their behavior. Changed source still incurs a CommonMark parse when gated code/link candidates require it; storage is proportional to source and accepted links.

Verification

  • Implemented and checked at c2175fc5bd79fed6928c37048e999287ac7e13e1 by gpt-6.1-sol through the Codex harness, Windows / Node 26.11.1, lockfile-matched scoped dependencies.
  • 95 shared parser/context tests pass across threadLinks, composerContextClipboard and composerContextReferences, including existing code/title/source-byte regressions and new prepared-result title/environment/source controls. One real React hook test uses mocked atom reads plus the actual atom registry and shared parser to verify no preparation on unchanged-source title/environment renders, updated labels, and preparation on source change.
  • Shared and mobile tsc --noEmit, targeted lint, scoped formatting and git diff --check pass. These packages expose no separate build script. No repo-wide checks, browser, server, provider or native/Hermes execution.
  • Local Node timing: 30 warmups, five batches of 50 calls, median ms/call, same source/reference/relabel workload. Two string scans / fresh preparation plus both consumers / reused preparation plus both consumers: 68 B 0.30447 / 0.11238 / 0.00078; 1,088 B 1.36146 / 0.63635 / 0.00944; 9,520 B 15.13115 / 6.39087 / 0.07199. Changed-source paths append an iteration value; unchanged-source uses one prepared result. This measures shared functions, not React rendering, native performance or precise allocation. No Hermes claim.
  • Fetched latest main before implementation: dd5f98eeecad5db5b10314296221df115f130fbd; reviewed its base diff. Continued existing f45a87b508cabd5453693f15fc315b20621436d3 ancestry under the explicit continuity exception, with no main merge or force push. Hosted checks/reviews for this new head are pending; historical green runs below do not validate it.

After merge

Parent #30588 remains at a364059587521142bf7324d2a1e32f9510a58155 and lacks upstream budget reduction 9e85538535c8553901351112ab02dd1dd62db5ee (Claude/Codex/MCP 20/20/40). The inherited Agent Context Budget failure is separate from this parser change. Parent owner @julius must integrate the coherent upstream change and verify its budgets before the follow-up inherits it normally. No generated-budget edit, label bypass, unrelated prompt change or main merge was made. Owner follow-up is already scheduled; no additional ping or watch started.

Implemented by gpt-6.1-sol through the Codex harness.

Superseded verification and historical evidence; not current-head validation

What Changed and Why

Issue: Follow-up to #30588 for #30576, targeting fix/issue-30576. Thread URLs inside valid multiline code spans were collected and rewritten at aa2a4bba628983f4b4c3a9da25bee2495c35356b.

Why this change was necessary: The regex excluded line endings and the closer map reset on each newline. Regex fences also ignored block context and could consume unequal backtick runs. Extending that scanner correctly would require block parsing. The shared package already depends on remark-parse and unified; this reuses their CommonMark parser and the parser-owned-offset approach in markdownMathRanges, adding no dependency.

New status quo: Lazily collect code/inline-code source ranges, then filter the existing bounded link candidates against them. Balanced code wholly inside a link label remains part of that link. Titles (including escaped delimiters, brackets and trailing horizontal whitespace) remain excluded. Collection and replacement share the same matcher; untouched source slices are preserved without AST serialization. URL and code-syntax gates avoid parsing ordinary messages. Web, desktop and mobile consume this shared behavior; provider adapters/contracts are unchanged.

Verification

  • Implementing agent at f45a87b508cabd5453693f15fc315b20621436d3: lockfile-matched scoped dependencies; 87/87 parser/context tests pass. New controls cover multiline spans, complete unequal runs, inline versus block fences, quoted/nested-length fences, paragraph boundaries and live links. Existing regressions remain intact.

  • Before correction, both multiline regressions failed collection; direct execution of aa2a4bba also confirmed relabeling changed the code content. After correction, the same inputs yield no references and remain unchanged.

  • Shared tsc --noEmit, targeted lint, formatting and git diff --check pass. Shared has no separate build script; no repository-wide checks were run.

  • Local Node 26 timing (100 warmed calls): plain 1.4 KB text ~0.001 ms/call; one live link ~0.018 ms; short multiline code/link ~0.197 ms; dense 8.8 KB/140-paragraph code/link input ~40.079 ms. Full parsing costs CPU/allocation on gated inputs: the dense sample showed ~9.4 MB end-of-loop heap growth and ~66 KB retained after GC, not a precise allocation measurement. This trades that cost for existing CommonMark block correctness rather than a second block parser.

  • Named-group RegExp.exec remains in use for Hermes compatibility; no new regex syntax. Hermes/native clients and current-head browser/provider behavior were not executed. Historical runtime evidence below does not validate this head. Hosted checks/reviews are pending at publication.

Implemented by gpt-6.1-sol through the Codex harness.

Independent performance and base readiness assessment

  • No implementation change in this assessment. Latest fetched main: 9e85538. Follow-up ancestry and parent fix(shared): hosted thread URLs inside other links stay as written #30588 at a364059 remain intact.
  • Node 26.11.1, extracted unchanged matcher bodies from aa2a4bb and f45a87b, identical dependencies, 100 warmups followed by five batches of 100 calls; median ms/call (prior/current): plain 1,440 B 0.00158/0.00068; live link 55 B 0.00151/0.00192; multiline protected span 45 B 0.00136/0.12310; mixed prose/code plus live link 999 B 0.01134/0.90220; 140-paragraph dense code/link 9,520 B 0.10369/10.02193. Measures candidate matching/range parsing, excluding schema decoding, replacement and UI rendering. Prior multiline results are incorrect, so speed alone cannot justify restoring them. These inputs differ from the earlier 8.8 KB benchmark.
  • Scope: URL gate avoids ordinary messages; code-syntax gate avoids plain links; parsing is lazy until a regex candidate exists. Mobile useLiveThreadLinkLabels calls collection and relabeling each render (ThreadFeed user/assistant Markdown and PendingUserInputCard), potentially two full parses. Composer paste conversion also calls replacement on web/mobile. Web Markdown rendering uses href parsing rather than this full-source matcher. Dense gated messages have a meaningful CPU/frame-budget risk; Node timings do not establish Hermes performance or actual frame drops. No speculative cache, new parser framework, dependency or AST serialization was introduced.
  • Independent local focused tests could not start with this worktree's missing dependency installation; attempted dependency reuse could not resolve required workspace/config imports. The 87-test result above remains attributed to the implementing agent, not independently rerun here. No browser, provider, full-repository tests or dev servers were run.
  • Current-head hosted CI run https://github.com/pingdotgg/t3code/actions/runs/41868807383 completed successfully, including aggregate Check, lint, build/typecheck, package/web tests and all eight server shards. Separate Agent Context Budget failed: https://github.com/pingdotgg/t3code/actions/runs/41868806962/job/126710804848 . Latest listed reviews remain historical (8c8ebdf/965262e), not approval of f45a87b.
  • Budget root cause: upstream 9e85538 (feat(server): agents ask for secrets through request_secret instead of chat #30257) changes real secret-request instructions/tool definitions and their budget test, reducing Claude 5153 to 5133, Codex 6883 to 6863 and MCP 47538 to 47498. This PR's two-file parser diff changes none of those inputs. Readiness is blocked on parent fix(shared): hosted thread URLs inside other links stay as written #30588's owner integrating that coherent upstream change into its base and verifying/regenerating budgets through AgentContextBudget tests; then this branch can inherit the updated parent normally. Merely editing generated numbers would be false. No unrelated main merge, label bypass or instruction trimming was performed.

Assessed by gpt-6.1-sol through the Codex harness.

Historical evidence (superseded implementation descriptions and statuses; not current-head validation)

Additional exact-head runtime verification reported by Maria at 38ed00b5bd03ade8bda915523e2bce3a0edbd8a9: #30665 (comment) . Her Linux real-web/Codex pass reproduced main's titled-link corruption and checked titles, escaped delimiters, trailing horizontal whitespace, balanced/literal backticks, code shielding, chip navigation, and intact provider context after corrections. She reports 76 focused parser/context tests and scoped checks passing. I inspected the report and final whitespace diff; I did not repeat her runtime pass. Native clients and remote/multi-environment behavior remain unverified by that pass. Prior head 38ed00b had 27 passing hosted checks; both inline findings remain resolved. That historical status does not establish checks or approval for later commits.

Simplification at aa2a4bba628983f4b4c3a9da25bee2495c35356b

Opus 5.5 removed duplicated backtick pairing without changing tests or public behavior. It reports 300,000 generated-input comparisons matching the preceding head and scoped typecheck/lint/format checks passing. The primary agent independently reviewed the source diff and reran both focused parser/context files: 75/75 tests pass. Generated-input comparison establishes equivalence to the previous implementation, not complete Markdown correctness. Native-client verification was not repeated. Hosted CI now passes at this head: aggregate Check, lint, build/typecheck, package and web tests, all eight server shards, agent-context budget and native fingerprint comparison succeed. Two other fingerprint check runs were cancelled and seven platform/preview checks skipped; none are pending. Both existing review threads are resolved. The PR is clean and mergeable, awaiting owner incorporation; prior-head runtime evidence above remains attributed and historical. Existing limitations around the regex's handling of unequal backtick runs and fence precedence remain unchanged.

Simplified by Claude Opus 5.5 through T3 Code; independently reviewed and tested by gpt-6.1-sol through the Codex harness.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-04T06:30:11.438310Z 8c8ebdf PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XS 0-9 changed lines (additions + deletions). labels Nov 4, 2026
Comment thread packages/shared/src/threadLinks.ts Resolved
@macroscopeapp

macroscopeapp Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Would Approve

Macroscope's review found this PR approvable — This adjusts Markdown thread-link handling to preserve code shielding and leave titled links unchanged. The reported code-span label corruption remains subject to the separate correctness blocking gate; no additional material risk requires human judgment.

Needs human approval because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8c8ebdf10c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/shared/src/threadLinks.ts Resolved
@github-actions github-actions Bot added size:M 30-99 changed lines (additions + deletions). and removed size:XS 0-9 changed lines (additions + deletions). labels Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

Note

🤖 OpenAI assistant responding on behalf of Elliot

P2: Preserve a whole link when its label contains a literal unmatched backtick. At 965262e, packages/shared/src/threadLinks.ts:43–47 rejects every label with an unmatched run, even when there is no closing backtick anywhere after it. In Markdown that backtick is literal text, not a code span. For example, formatHostedThreadLink(ref, "Fix \typo")` produces:

[Fix `typo](https://app.t3.codes/threads/one/same)

The scanner rejects the whole-link match, then matches its href as a bare URL. Relabeling to Title therefore produces the broken nested link:

[Fix `typo]([Title](t3-thread://v2/one/same))

I reproduced this with the exact scanner/replacement logic extracted from this head in Node 24; I did not run the repository test suite. The balanced-code fix works, but a thread title with a lone backtick still corrupts a copied link. Preserve the whole candidate when the unmatched label run cannot actually form a cross-boundary code span, while retaining the new shielding cases. Add a regression for a lone literal backtick with no later matching delimiter.

@maria-rcks

maria-rcks commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol on behalf of Maria

Verified in a real dev environment

reproduced titled-link corruption on github/main (8b44f42b14) in a separate worktree. pasting a hosted thread link with a Markdown title incorrectly inserted a chip inside the destination. used vp i, isolated app state, one background dev server at a time, repository playwright, and /usr/bin/google-chrome on linux. the project, threads, and codex gpt-6.1-sol replies were created through the app, without mocks or seeded data.

the original pr head fixed that case but still corrupted lone-backtick labels. further checks found bracketed/escaped titles, trailing title whitespace, and a later code opener following a literal backtick. reproduced each in the real composer and with failing rows in existing tests. pushed scoped corrections to this pr's existing head branch without force. final head: 38ed00b5bd03ade8bda915523e2bce3a0edbd8a9.

after restarting the corrected app, verified:

  • all three title forms stay literal, including brackets, escaped delimiters, and trailing horizontal whitespace.
  • balanced and lone-backtick labels become one chip without leftover text.
  • cross-boundary spans, mixed backtick runs, and fenced code keep urls literal; a following live link still becomes a chip.
  • clicking the chip opens the original thread.
  • real codex receives the intact literal text and reads the original thread through the t3 thread tool.
blacksmith: vp test run packages/shared/src/threadLinks.test.ts packages/shared/src/composerContextReferences.test.ts
76 passed
blacksmith: vp run check:changed HEAD (before each correction commit)
format, lint, knip, affected typechecks, selected tests: pass
running-server CLI: t3 thread show --base-dir <isolated-home> --json <verification-thread>
providerInstanceId=codex model=gpt-6.1-sol status=completed activeRunId=null
provider read: reference thread ready.

main, before:

main incorrectly inserts a chip inside the titled link

corrected pr, matching input:

corrected pr preserves titles and code while converting the live link

paste checks and navigation, including the additional title and backtick cases:

pasting titles and code, then opening the original thread

real provider result:

codex confirms literal content and reads the original reference thread

Not verified

native ios/android clients, electron shell behavior, remote/tunnel or multiple-environment navigation, and other providers were not exercised in this linux web pass. the full hosted test/build suite was not rerun here; scoped blacksmith checks passed. no merge, rebase, force push, or label changes were performed.

three independent-review rounds found the additional cases above. the last round approved the preceding head in one review and found trailing title whitespace in the other. that finding was reproduced, corrected, and checked; the final whitespace correction has not had another independent review because the review-round budget was reached. this is runtime verification, not a merge-readiness claim.

@ElliotDrel

Copy link
Copy Markdown
Contributor Author

Note

🤖 gpt-6.1-sol responding on behalf of Elliot

Added your current-head runtime report to the description with attribution and retained its native/remote and hosted-suite limits. I also inspected the final 38ed00b whitespace-only diff: the title group now consumes trailing horizontal whitespace and the existing table covers double-quoted, single-quoted and parenthesized titles. No additional finding from that narrow source review; it is not a repeated runtime pass or merge-readiness claim. No further code change is needed from this report.

ElliotDrel and others added 3 commits November 4, 2026 08:31
The label scan paired backtick runs twice: once inside each label, then
again across the line to tell a cross-boundary opener from a literal
backtick. Both answer the same question, so a single map from each run
to its same-length closer on the line now serves both. A label skips
spans that close inside it and yields to one that closes past it.

Behavior is unchanged: a 300k-input differential fuzz against the prior
scanner matched exactly, and adversarial 1 MB inputs stay linear.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Nov 4, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants