Skip to content

Feat/issue 271 search metadata - #272

Open
Liu233w wants to merge 8 commits into
mainfrom
feat/issue-271-search-metadata
Open

Feat/issue 271 search metadata#272
Liu233w wants to merge 8 commits into
mainfrom
feat/issue-271-search-metadata

Conversation

@Liu233w

@Liu233w Liu233w commented Aug 14, 2026

Copy link
Copy Markdown
Owner

No description provided.

Every page sent a <title> and nothing else, so a search engine built its own
snippet out of the first text it found. On the home page that is the terminal
banner ($ pip install ojhunt), which tells a reader nothing about the project.
A shared link showed no preview either.

base.html.jinja now carries a meta description, a canonical link, and the Open
Graph tags. Each page declares its summary in a meta_description block; the
home and About pages inherit the default, which summarises the project as a
whole. Descriptions stay at 160 characters or shorter, where the snippet is cut.

The easter-egg routes answer 200 on 40+ scanner paths (/admin, /.env,
/wp-login.php). Those pages and the 404 page now send noindex and no canonical
URL, so they stay out of the index.

Page routes render through the new render_page() helper, which supplies the
absolute base URL and the canonical URL from the request — the same
request.base_url pattern robots.txt and sitemap.xml already use.

Resolves #271
The format hook runs `ruff check --fix` after every Python edit, so an import
added before its first use is deleted before the next edit runs. It happened
twice in one session and surfaced both times as a NameError far from the cause.

The page-metadata work also produced a doc section that restated what the code
already said. Sharpen the routing rule that should have stopped it: prefer a
test that discovers what it checks over a written rule, and keep prose for the
intent a test cannot express.
@mergify

mergify Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

The routing table in docs/development.md told an agent where to look, but
nothing made it look at the moment it mattered. Two conventions were missed in
one session: comments were written above asserts instead of inside them, and a
fact already covered by docs/dev/python.md was duplicated into hooks.md.

Conventions tied to editing a kind of file move to .claude/rules/*.md with
paths: frontmatter, so they enter context when a matching file is opened rather
than waiting to be looked up. Six rules cover Python, tests, e2e, the web layer,
docs and hooks.

Three kinds of knowledge stay in docs/dev/, because no file pattern can trigger
them: a new crawler starts as a file that does not exist yet, ops work touches
no repo file, and questions like "does this warrant an ADR" precede any file.
The routing table now carries only those. The update-env skill records the split
and the compaction caveat.

format-lint-python.sh gains one check: a comment directly above an assert in a
test. It reads the edit payload rather than the file, so the cases already in
the suite do not fire on every unrelated edit.
A comment above an assert is invisible when that assert fails; a message
prints. .claude/rules/python.md already says so, but 45 sites across 27 files
predate the rule, which makes it read as optional to anyone skimming the suite.

Most were one of two boilerplate lines repeated across the crawler tests. Those
became messages that state the invariant rather than restating the call —
"solved_list must hold one entry per solved problem" instead of "Check that
solved_list has the correct length". The rest carried real reasoning and moved
into the message verbatim.

This clears the way for a lint rule to enforce the convention repo-wide.
The comment-above-assert check was an awk program inside
format-lint-python.sh. Being line-based it could not tell code from a string
literal, so it flagged the example snippets inside the very test file that
documents the rule. It also read the edit payload rather than the file, purely
to route around violations that already existed in the suite.

Rules now live in lint/rules/. ./doit.sh lint runs them over the repo and the
hook runs the same files over the one file that changed, so the two cannot
disagree.

This rule is Python, not ast-grep YAML, because it needs source position. A
trailing comment and an own-line comment are the same shape in the parse tree,
and the YAML version reported one violation three different ways depending on
what came after it: the line below when another assert followed, nothing at all
when a non-assert followed or the body ended, and a false positive when the
trailing comment belonged to an assignment. sgconfig.yml and lint/rule-tests/
stay for rules that are purely structural, where YAML reads better than code.

tests/lint/ pins which line each case is blamed on, including the cases that
must stay silent. rules_are_tested_test.py discovers rules from the directory
and fails when one ships without tests, so this is not a convention to
remember. ./doit.sh lint-rules joins full-check.

The parser-based rule found four trailing comments the line-based one missed;
those are folded into their assert messages.
@Liu233w
Liu233w force-pushed the feat/issue-271-search-metadata branch from da940e8 to c774d53 Compare August 14, 2026 10:02
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.

1 participant