@gurupanguji

Bare URL Markdown Binding Design

Goal

Add a repository check that catches stray bare blog URLs in markdown post bodies and asks the author to wrap them in markdown link syntax before commit or push.

The target problem from issue #86 is this:

https://gurupanguji.com/blog/2026/03/18/a-website-to-destroy-all-websites/

The accepted shape is this:

[https://gurupanguji.com/blog/2026/03/18/a-website-to-destroy-all-websites/](https://gurupanguji.com/blog/2026/03/18/a-website-to-destroy-all-websites/)

Scope

Version 1 should stay narrow.

This solves the actual bug without turning the validator into a generic markdown parser for every possible URL shape on day one.

Non-Goals

Existing Enforcement Path

The repository already routes post policy through one shared validator:

That shared path is the right place for this rule. Adding the rule there means:

Detection Strategy

Use a small line-oriented scanner over the markdown body after front matter has been removed.

The scanner should:

  1. Track whether it is inside a fenced code block.
  2. Ignore inline code spans on the current line.
  3. Ignore raw HTML tags and attributes on the current line.
  4. Ignore URLs already wrapped in markdown link syntax.
  5. Flag any remaining bare https://gurupanguji.com/blog/... URL matches.

This is better than one giant regex. Markdown has enough local structure that a tiny state machine is easier to trust and easier to test.

Accepted And Rejected Cases

Reject

See this:
https://gurupanguji.com/blog/2026/03/18/a-website-to-destroy-all-websites/
This post explains it better: https://gurupanguji.com/blog/2026/03/18/a-website-to-destroy-all-websites/

Accept

[https://gurupanguji.com/blog/2026/03/18/a-website-to-destroy-all-websites/](https://gurupanguji.com/blog/2026/03/18/a-website-to-destroy-all-websites/)
[older post](/2026/03/18/a-website-to-destroy-all-websites/)
`https://gurupanguji.com/blog/2026/03/18/a-website-to-destroy-all-websites/`
```text
https://gurupanguji.com/blog/2026/03/18/a-website-to-destroy-all-websites/
```
<iframe src="https://www.youtube.com/embed/example"></iframe>

Error Shape

The validator should emit an actionable error with file path and line number.

Suggested shape:

_posts/2026-03-24-example.md:42: bare blog URL found, wrap it in markdown link syntax: https://gurupanguji.com/blog/2026/03/18/a-website-to-destroy-all-websites/

This keeps the failure cheap to fix.

Test Plan

Add unit tests to tests/test_validate_posts.py for:

  1. bare blog URL in markdown body fails
  2. markdown-wrapped blog URL passes
  3. inline-code blog URL passes
  4. fenced-code blog URL passes
  5. raw HTML attribute URL passes
  6. existing snippet validation tests still pass

Risks

False positives

The main risk is flagging URLs in valid non-prose contexts such as code blocks or HTML embeds.

Mitigation:

False negatives

A narrow first version will miss some future bare URL shapes outside gurupanguji.com/blog/....

Mitigation:

Rollout

  1. Implement the validator helper in scripts/validate_posts.py
  2. Add unit tests in tests/test_validate_posts.py
  3. Run validator tests locally
  4. Run the repo validator locally
  5. Land via branch and PR

Decision

Issue #86 should be solved by extending the shared validator, not by adding a bespoke hook check. One rule, one test surface, one enforcement path.