v0.33.0

feder-cr/AIHawkv0.33.0Sep 9, 2026by github-actions[bot]

AI Summary

This release focuses on UI cleanup and accessibility improvements, removing redundant elements like the model header and token meter. It refines typography for better readability and fixes critical layout overflow issues on narrow screens. Additionally, it introduces automated validation gates to prevent common CSS and layout bugs.

Key Highlights

  • Removed redundant model header and token meter for a cleaner UI
  • Improved typography by reducing type sizes and increasing body text readability
  • Fixed layout overflow issues on narrow screens by stacking panes
  • Introduced automated CSS validation gates to prevent unbalanced braces
  • Enhanced accessibility compliance by enforcing strict layout rules

Breaking Changes

  • The visual token meter has been completely removed (counting functionality remains for transcripts)
  • The model header (H1) is no longer displayed
  • Layout changes for the address bar and pane arrangement on screens under 720px

New Features

  • CSS validation gate to check for unbalanced braces
  • Layout validation gate to ensure narrow layout overrides correctly
  • Automated test for the visual token meter removal

Full Release Notes

* The header says the model and nothing else (0.33.0)

Two things came off the top of the conversation. The product's name, which said
what the tab, the window and the address bar already said. And the token meter,
which put a number that grows all session long in the corner of a screen nobody
opens to read accounting.

The heading did not go with the name. It is off-screen now and it is
load-bearing where it cannot be seen: the answers' own headings start at h3 on
the reasoning that a name sits above them, so deleting it leaves every one of
them hanging under nothing. An h1 nobody can see is the most deletable-looking
line on the page, so a gate holds it there - and holds the way it is hidden,
because `display:none` and `visibility:hidden` would take it out of the
accessibility tree as well, which is the only place it still lives.

And what had been keeping that group on the right was the meter. `margin-left:auto` lived on it, so taking it away dropped the model and Clear against the left edge. The push belongs to the first of whatever survives, not to whichever element happens to be sitting there.

The meter went the whole way. Not just the element: the rule that styled it,
the function that filled it, the event that fed it, and the two places in the
stream that treated that event as state rather than conversation. What stayed
is the counting, because it is what the transcript is saved with, and a number
put back anywhere later is a question of where to draw it rather than of
measuring it again. It has a test of its own now, since an accounting nobody
watches is the kind that stops working with nothing going red.

And removing the case for an event the server still sent put a line of raw JSON
at the end of the transcript, under the last answer: the switch ends with a
`default` that appends the text, which is right for a kind the server learns
before the page does and wrong for one the page used to draw. 528 tests were
green and it was found by opening the page. So the two sides are compared now:
whatever the server can emit, the page names. That gate would have caught this
in one run.

Seven known-bad mutations, all killed: three on the heading, four on the two sides of the event contract.

* Three type sizes where there were five, and a body you can read

Measured on the running page: the conversation column drew NINE size/weight
pairs, at 11, 12, 13, 14 and 16px. Four sizes inside three pixels. A step of
1.08 is not read as a step, it is read as an accident, and a scale that fine is
a scale in name only.

It is 12 / 15 / 18 now, on one ratio, and the levels that used to sit a pixel
apart share a size and are separated by weight and colour instead - which is
the stronger signal and was already how the page carried its other tiers.

The body went from 14 to 15. This column exists to be read, and 14 is under the
floor every source puts on reading text. The measure is unchanged at 71
characters, inside the 65 to 75 the same sources give, because the column was
already wide enough to carry the larger size.

Monospace stays at 13 and now says why in the file: a mono face runs wider and
reads larger at the same pixel, so it does not belong on a scale built for a
proportional one - and the step track is measured against it, so moving it
moves a threshold a gate checks.

The last two hand-written sizes are gone with it: the address bar and the
sessions band each carried a literal that belonged to a token.

The gate changed shape rather than moving. It demanded every pair of levels be
at least two pixels apart, which forbade sharing a size as well as the hair
that was the actual defect. Now a pair may share a size - and then something
else has to separate it - or step by two pixels or more, and never the middle.
It also holds the body above the reading floor and every distinct size on one
ratio. Four known-bad mutations, all killed.

* The panes stack before the window runs out of room

Measured in a frame 320px wide, which is what WCAG 1.4.10 asks a layout to
survive: the document scrolled sideways to 482px. The conversation was squeezed
to 270, the browser pane was allotted nothing at all, and its bar - the address,
the Live and Frozen pair, the layout picker - was drawn past the edge of the
window with no way to reach it. Under 720px the two panes stack now, and there
is no sideways scroll at any width from 320 to 1400.

The bar itself wraps rather than sitting on a fixed line, and its height became
a floor instead of a ceiling so a second row is not clipped. The address can
shrink to nothing but the two control groups cannot, so three fixed widths in a
row had nowhere to go.

Two things about how this was found, both worth keeping.

The first measurement was wrong and said so late. The `zoom` property scales
what is drawn and does NOT move the CSS viewport, so no media query fires under
it: a pass "at 400%" reported a failure that was an artefact of the instrument.
An iframe of a fixed width has a viewport of its own. These numbers come from
that.

Then the rule was written above the rules it overrides. Same specificity, so
source order decides, and it changed nothing while measuring as though the
breakpoint did not exist. Moving it left its closing brace behind, and an
`@media` block missing one does not fail - it swallows every rule after it. The
whole page above the breakpoint quietly lost its header height, its bar and its
composer width, with nothing red anywhere, because a stylesheet with an
unbalanced brace is still one the browser parses.

Both now have a gate. One counts braces, which is the whole check and is
enough. The other holds the narrow layout after the layout it overrides. Four
known-bad mutations, all killed.