Skip to content

Blog ·

When the title cannot be the heading

A rule saying an article's title equals its heading collides with a sixty character limit. Five languages needed the pattern that already existed.

By Provibr

One of our articles carries a word in its title that matters: vulnerability. It is a piece about a scanner that sends zero bytes, and without that word the title describes a different thing.

In five of the nine languages the word was gone. Not from the body, from the title and therefore from the browser tab, the search result and the social preview. The task was to put it back in all nine.

That turned out to be impossible in the form it was written down, and the interesting part is why.

Two rules that cannot both hold

The instruction was: the title, the social title and the heading are one string. Say the same thing in all three places. That is a good rule and it is the rule we wrote down after a reader found a link promising one thing and a page claiming another.

The other rule is a length band. The rendered page title has to be between twenty and sixty characters, suffix included, because that is what fits before a search result truncates it. That band is not a preference; the whole corpus of 850 generated files sat inside it, with nothing outside.

Put the missing word back and the full heading is 68 characters in Dutch and Italian, 70 in Portuguese, 71 in Spanish and French, and 75 in Romanian. English and German land on exactly 60, which is a coincidence worth noticing: the two languages where the honest heading happens to fit are also the two where the rule looks like it works.

So one of the two rules had to give, and neither is optional. The heading has to name the subject and the title has to fit.

The pattern was already in the house

The resolution was not invented for this. Of the 850 generated articles, 197 already had a title that differs from the heading. It is a normal thing for an article to do: the heading is a sentence and the title is a label.

French was already doing it on this exact article. Its title reads as a label with a colon, its heading as a question the body answers. Nobody had recorded that as a decision; it was simply what somebody wrote when the sentence did not fit.

So the fix is that five titles adopt the shape that nearly a quarter of the corpus and one of the nine languages already used, and the headings carry the full sentence. The word is present in the title, in the social title and in the heading, and it does not have to be the same string in all three to be the same claim.

The rule survives, but it needs restating: what has to hold is that a reader arriving from a link recognises the page. Byte equality was a convenient way to enforce that on the languages where it happened to be possible.

Why the existing guard could not have found this

We had just built a guard for exactly this family of problem: a link text that names an article differently from the article's own title. It was green here, and it was green for a structural reason rather than by luck.

This is a title defect. The titles had lost a word, and the link texts pointing at them had been shortened to match during the round that built the guard. Both sides agreed. A comparison between two things that were changed together cannot see that both are wrong.

What did find it was version control. The commit that repaired the link texts showed three of them being shortened, in Dutch, Italian and Portuguese. The report only mentioned two. Reading a diff rather than a summary is what turned a two item task into the real shape of the problem.

A guard that cleaned up after us

There is a small sequence at the end of this that is worth writing down, because it is the guard behaving better than the people using it.

After the titles were changed, the link name guard fired once, on a Dutch link to a different article. That looked like collateral damage and an exception was recorded for it, with a reason.

Then the titles were adjusted again to bring them inside the length band, and the finding disappeared. The exception was now dead: a line in an allowlist matching nothing.

There is a test in that guard whose only job is to fail when an exception is never hit. It failed, and the line came out. The final diff against the guard's directory is empty, which is the strongest statement available: the repair required no change to the rules at all.

An allowlist that only grows is a document of everything anybody ever gave up on. An allowlist that removes its own dead entries is a list you can still read in a year.

Small things learned in passing

A colon in a title is a shape, not a decision that was measured. It reads as a label rather than a sentence, it shortens well, and French had already picked it. That is written down as a choice made on form, because pretending it came out of a measurement would be dishonest about which parts of this were measured and which were taste.

A length band is a per language constraint even when it looks global. The same sentence is eight characters longer in one language and fifteen in another, and any rule expressed as "the same string everywhere" will break first in whichever language is most verbose. Romanian is usually that language here.

And a task written as a two line instruction can contain a conflict that only appears when you try to satisfy both halves. The right response is not to satisfy the half that is easier to check.

What we would write down

  1. When two rules collide, neither of them is wrong. Work out which one is the guarantee and which one was the convenient enforcement of it.
  2. Byte equality is a proxy for recognisability. State the thing you actually want.
  3. Look for the pattern in the corpus before inventing one. Ours was already in 197 of 850 files.
  4. One language doing it already is evidence, even when nobody wrote it down as a decision.
  5. A guard cannot see a defect where both sides were changed together. Agreement is not correctness.
  6. Read the commit, not the summary. The diff had three entries where the report had two.
  7. A test that fails on a dead allowlist entry cleans up after you. Ours removed an exception we had just added.
  8. An empty diff against your rules is the strongest result of a repair. It means the rules were right.
  9. Length limits are per language. The same sentence is fifteen characters longer somewhere.
  10. Say which decisions were measured and which were form. Mixing them costs the measured ones their credibility.

For clarity about what this is: the content build produced 850 articles with no warnings where it previously produced five, the content check was 851 of 851 generated files byte identical, the web suite 4594 green, the type check clean, the linter with no errors, the byte sweep over the 25 touched files unchanged on every count, the diff exactly 174 lines in and 174 out, the layout sweep 27 of 27 at 390 pixels across the article in nine languages, the blog index 54 of 54 and six Ukrainian articles 18 of 18 against a production build. Not proven: there is still one reader per language, and the choice of the colon form is a decision about shape rather than a measurement.

From the platform work on Provibr. Where the rule about titles and links came from is in three faults no script could see, and how the guard that enforces it distinguishes a shortening from a replacement is in two names for the same article.

Start with one host and one agent

Create an account, install the agent with a single command and connect your first Proxmox host. The trial runs for 14 days and asks for no payment details.