# Phase 7 — Wiki UX

Arc started 2026-07-22, after Phase 6. Sections are Roman numerals and steps within them are lettered; each step's title says what it does, followed by a sentence on what was proposed and, once worked, a few on what was done and anything learned. Marker legend: ▶ being worked on, ⚑ implemented and waiting to be reviewed, ✓ done, ✓✗ closed by deciding not to do it, ? open decision, unmarked = planned.

## Arc Post-Mortem Summary

This arc finished the wiki's editing and resource surfaces. The page-resource folder gained its listing, upload, rename and move controls (I); the editor gained a live preview beside the source and then a markup toolbar over it (II); categories became a content tool, with pages filed under them and front pages built from them (III); and a named witness can now take their part in a secret ballot by following a mailed link, so a ballot no longer needs every witness at one form at one moment (IV). The folder interface, the page settings and the mail settings were documented in five new help pages, and the page settings screen gained marks that open them (V). Alongside the planned work the arc drew Yioop's own code symbols and mail in pure PHP, moved the mail settings to Server Activity, and left the secret ballot working end to end: invitations that name the machine they came from, parts kept until the last witness answers, and a count that opens the votes.

## What this arc is for

The wiki is where a group keeps its shared pages, so its editing and resource surfaces are what a group touches most. This arc finishes the page-resource folder UI (I), gives the editor a live preview and then a markup toolbar (II), makes the category mechanism a real content tool (III), completes the email witness flow for secret ballots (IV), and documents the folder UI once it is finished (V).

1. ✓ Finish the page-resource folder UI. The folder is what a group touches most, so it is finished first.
   1. ✓ The page-resource folder reflows as a card grid. A fixed table with four hard column widths gave the folder a 502px floor. The grid is sized by a container query on the folder itself.
   2. ✓ Rows in the folder can be picked and acted on together. Rows are picked in the browser. Nothing is sent until an action is asked for.
2. ✓ Give the editor a preview and then an assist. The preview comes first, since the toolbar shows its result.
   1. ✓ A wiki page shows a live preview beside its source. It renders in the browser through the existing parser port, so typing costs no request.
      1. ✓ The two panes share one window. It is of settled height and split by a draggable bar. Under 52rem the preview sits above the source.
      2. ✓ The preview opens from a book icon and starts closed. A page that is never previewed pays nothing for the feature.
      3. ✓ Picking words out in either pane marks them in the other. They are brought into view. The pane being worked in never moves.
      4. ✓ Charts, tables, math and search boxes all draw in the preview. Each is rendered from what the markup carries, so nothing is fetched.
      5. ✓ A resource shown as an example is not drawn. Text inside nowiki is left as itself, in both parsers.
   2. ✓ Buttons insert wiki markup at the cursor. The textarea stays the source of truth and the preview shows the result.
      1. ✓ The preview follows what a button puts in. A browser raises nothing when a script writes into a field, so the preview went on showing what stood there before the markup was added.
      2. ✓ What a button puts in can be taken back with the undo key. The whole field had been rewritten, which throws away what the browser remembers of the writing; the words now go in the way typing puts them in.
      3. ✓ A picture stored with a page now shows in the preview. The preview asks the site for such a picture by group and page, and it was asking with both of those set to zero, so the site had nothing to look up and the picture came out broken. The page being edited knows its group and its own id, so both are written onto the editing field as data attributes and the preview reads them from there.
3. ✓ Make the category mechanism a real content tool, so a group can run as a newsroom. A wiki page becomes an article, other pages front those articles, and a category is what ties the two together. Today a journalist types the icon, the open-graph properties and each category tag by hand, in two places, with nothing checking the spelling. The five steps below remove that typing and make a category something the site knows about rather than a string in a body. To-do item 20.
   1. ✓ A front page collects articles into a shape a writer chooses. Such a page is laid out by picking a shape and naming what fills each of its places, rather than by typing tags. What is saved is ordinary wiki markup, so anyone can read or edit the page without the form.
      1. ✓ Four shapes are offered, each drawn as a thumbnail. A writer picks by the look of it: a lead story with headlines beneath, a row of cards, a grid of four, and stacked sections. The shapes and their places appear as soon as the kind is chosen rather than after a save.
      2. ✓ Each place says what it holds. A lead holds an article and the headlines beneath hold a category, so neither asks; anywhere else offers the choice, then a page to name or a category to pick from the group's list.
      3. ✓ The settings show what belongs to the kind of page being made. Every kind showed every control, so an alias page offered a border and a front page offered a resource path. One table says which parts each kind uses, the form follows it as the kind is chosen, and the settings offer saving alone.
      4. ✓ One of a set of buttons stands for the whole set when a form is sent. Every button was being sent, so the last of them stood for the choice whichever a person had picked.
      5. ✓ The shapes are given the styling that makes them look like themselves. Cards lay along a line and wrap, the grid is two across and one on a narrow window, sections stack with a rule between, and headlines under a lead are a plain run of names. The elements a list is made of are each told how to lay themselves out, since a browser lays an unknown element along the line like a word.
      6. ✓ A list of what is filed under a name draws at all. The parser left the words asking for a list as words, while the site looked for a mark those words never became, so no list had ever drawn. The parser leaves that mark now.
   2. ✓ A group knows its own categories and what its pages are for. Everything after this leans on the group's list existing, since a chooser can only offer what the group knows.
      1. ✓ A group's settings hold the names its pages may be filed under. Each name stands on its own row with a mark that drops it. A field below adds another, the way a domain is added on the servers page. A name already standing, or one holding a comma, is passed over. What is sent is still one line with commas between, kept in a hidden field and rebuilt as rows come and go. A front page's category pickers offer these alongside any name the group's pages are already filed under.
      2. ✓ A group says what kind of page a new page starts as. A newsroom sets it to news article, so every page a journalist creates begins as one. A page that already exists keeps the kind it was saved with. The setting is labeled for what it holds rather than for what it does. Its name and the categories' name each carried a colon the markup supplies, so both read with two.
      3. ✓ A wiki page can be a news article. A new page kind carrying what an article needs and nothing else. The two new group settings live in columns of their own, added by a version step so a database already in use moves forward. Naming the columns in the seeding inserts keeps them working when another column is added.
   3. ✓ A journalist writes a news article without leaving the editing screen. Writing one today means filling in the settings panel for the title, the author, the thumbnail and the description, going back to the body to type the category tags, and then typing the open graph properties by hand. All of that moves onto the editing screen, and saving fills in the rest.
      1. ✓ The title, author, thumbnail and abstract sit above the writing area. They are the first things a journalist needs and were three clicks away in the settings panel. The four are moved out of that panel onto the editing screen rather than drawn a second time, so no field is asked for twice. The description is labeled Abstract and the icon Thumbnail while a news article is being written.
      2. ✓ Categories are chosen from a list beneath the abstract. They had to be typed as tags in the body, where a misspelling filed the page nowhere. The group's own names are offered, and a name chosen stands as a row with a mark to drop it. What a page is already filed under is read from its body, so opening one shows what is there.
      3. ✓ Saving writes the tags, the head and the open graph properties. A journalist should not have to write the same category in three places, nor know what an open graph property is. Saving writes the category tags into the body, so searching by category still finds the page; puts the title, author, thumbnail and abstract into the page's head; and writes og:title, og:description, og:image, og:url and a property for each category. The tag also files the page under that category, which is a link from the page to itself carrying the category's name.
      4. ✓ A reader can see which sections an article is in and follow them. Nothing on a finished article said what it was filed under, so a reader wanting more of the same had nowhere to go. The names stand under the article's last words, each a link to the list of what else is filed there.
   4. ✓ A category list becomes a real listing. A page drawing a category could ask only for a name and a class. It can now say how many, in what order and which page of them, the list it draws is ordinary markup, and a category has a page of its own to lead to.
      1. ✓ A list takes named settings. How many to show, in what order, and how to style them, given by name rather than by position, and any of them may be left out. A list written as a bare set of classes still reads, so pages already written go on working.
      2. ✓ A long list offers the rest. A front page showing one section of a busy group gave a reader the first few and no way past them. Where more are filed than were asked for, a line beneath the list says how many there are and leads to all of them.
      3. ✓ A category has a page of its own. Asking for a category gives a page naming it and listing what is filed under it, built as it is asked for rather than kept, so a category has one from the moment anything is filed under it. Every link to a category leads there: the tags beneath an article and the way on beneath a listing.
      4. ✓ The list a category becomes is ordinary markup. It had been tags of our own invention, which carry a name but no meaning, so nothing reading the page for someone could tell it was a list of links. It is now a list of links.
   5. ✓ A category can reach another group, and the forms are written up. A front page in one group collects articles filed in another, written the way the site already writes a page in another group.
      1. ✓ A place holding a category may name another group. Wherever a category's name is filled in on a front page, it may be written group@category to take a category from that group instead of this one.
      2. ✓ The category forms are written up on the syntax page. Neither the tag nor the list appeared there. Delivered as wiki help source in a text file, since that page is generated.
4. ✓ Let named witnesses take part in a secret ballot by email. Today a ballot cannot start until every named witness has typed their password into the same form, and cannot be counted until they all do so again. A witness should be able to take their part alone, by following a link sent to them, while the old way keeps working and the two may be mixed in one ballot. To-do item 21.
   1. ✓ How the parts are held while the witnesses catch up. The old way has one moment of risk: after the last witness types their password, every witness's root sits in memory at once, where somebody with the run of the server could take them. Spreading the witnesses over hours widens that moment, so the parts must be held in a form the site cannot read while it waits. When the witness screen is first shown, the site makes a pair of keys, keeps the secret one in a file of its own under the temporary directory, and writes the public one into the ballot's secrets file with that file's access time. Each part that arrives is sealed with the public key. When the last part arrives the access time is compared against the one written down: a key file that has been read means the parts could have been opened by somebody else, and the ballot must be begun again. Otherwise the parts are opened in memory, the ballot's keys made as they are today, and the key file and both sections erased.
   2. ✓ A ballot can keep a witness's part until the others catch up. The part is sealed with the round's public key and kept in a shares section of the ballot's secrets file.
   3. ✓ A witness can be invited by a link that works once. The link carries the page, the ballot, the witness, which stage it is for and when it stops being good, signed with the site's own key. It lasts a day, which a deployer may change, and a fresh set of invitations ends the set before it.
   4. ✓ The initialization screen offers both ways. Each witness row has a button to email that witness instead of typing a password, and there is one to email them all. A witness whose part has arrived is shown as received rather than asked again. Neither button appears where the site cannot send mail, nor where the only witness owns the page.
   5. ✓ Pressing an email button sends the invitation. Sending works out that witness's link and mails it, and writes a fresh nonce into the ballot's secrets file, which ends every invitation sent before it. The mail is handed to the mail server as the button is pressed. Left in the folder the media updater drains, it would sit there unsent wherever that updater is not running. A witness counts as written to only where the server took the message.
   6. ✓ Following the link takes that witness's part. The link opens a screen asking that witness for their ballot password. A link is refused where it has expired, where this site did not send it, where a fresher set has replaced it, and where that witness has already acted.
   7. ✓ The round is sealed behind a key file the site watches. Opening a round makes the pair of keys and records the key file's access time; closing it deletes the key file and erases both sections. The site can also say whether a read moves an access time where that file lives, by asking the file system rather than by knowing anything about the operating system, so a warning can be shown where the watch would be silent.
   8. ✓ The screen warns where the watch would be silent, and the ballot opens once every witness has acted. The start form says so where reading a file does not say that it was read. When the last part arrives the parts are opened, the ballot's keys are made from them the way the single form makes them, and the key file and both sections are erased. A round whose key file was read is refused and the ballot must be set up again.
   9. ✓ Closing the poll works the same way. The closing screen offers the same two ways, and counting proceeds once every witness has answered again. Counting needs the value each password makes, so a witness answering by mail has theirs worked out from the value the ballot drew for them at the start and kept sealed. The key file is not watched here, since the shares are used once and everything is about to be opened anyway.
   10. ✓ The watch on the key file catches a read on the file systems people actually use. A file written once has the same access time as change time, and macOS by default and Linux mounted the usual way move an access time on a read only when it already lags. The key file's access time is now set behind its change time when the round opens, so the first read moves it. Both times are recorded and compared, so a change is caught even where a read is not, and the site's own reading of the key puts the times back.
   11. ✓ Fixes found while testing the ballot. A witness round wrote into the secrets file, and that file existing is what says a ballot has begun, so merely reloading the start screen moved the poll to voting. The round now waits in a file of its own. Editing a user in Manage Users no longer asks for a password that was not changed, and a preview honors a page's table-of-contents setting, which it could not see because the setting lives in the page head and a preview parses only the words.
   12. ✓ The flow is tested where it can go wrong. Six ways of failing are held in place by cases in the signin model's test. Why a link is turned away moved out of the screen into the model, so each can be checked on its own: expired, forged, from a replaced set, or already acted on. A witness who never answers leaves the ballot unmade, with the part that did arrive still sealed, and giving up takes both files away. Counting refuses a password that differs from the one given at the start, whether it is typed or worked out for a witness who answered by mail. A round whose key file was read was already covered.
5. ✓ Document the wiki resource-folder interface. Most of it is written already, in what the wiki syntax page has gained. What is left is the help a writer needs while looking at a page's own settings, and one pass over the syntax page so it reads evenly. Written as wiki help source and delivered as text files, since generated help pages are not patched. To-do item 37.
   1. ✓ Write the three help pages a page's settings will point at. Wiki Page Locales says that each language holds its own copy of a page with its own history, tells a page's name apart from its title, and shows how an alias gives French readers café while the words stay in one place. Wiki Page Types describes all ten types the dropdown offers and the templates that join them, saying for each what a reader can do on such a page. Wiki Page Properties says which settings a page shows depends on its type, lists the ones every page has, then the ones a media list, a share wall, a shortener, an alias, a repository and an article each add. Two more go with them: System Emails, for the field-set on Server Activity, saying what sending with the built-in client does where this machine runs a mail server and where it does not, what the queue costs, and where to look when nothing arrives; and Account Registration rewritten, since the mail settings it described have moved, leaving the four ways an account is obtained and a pointer to where mail is now set. The field-set on Server Activity carries a help button opening the first of those. Each page was drawn through the wiki parser to see its headings, lists and links come out as markup rather than as text.
   2. ✓ Put the links on the page settings screen. A question mark follows the locale dropdown and another follows the page type dropdown, each opening the help for what that choice means. A third is set opposite above a rule that opens the settings beneath, since which of those a page shows depends on the type chosen just above, so one mark covers them all rather than each carrying its own. The two screens that draw a page's settings both got them, and the rule is drawn in one place they share. Measured on a running site: all three marks name their help page, and the rule follows the third. Putting a mark on that screen showed up an older fault: where a reader came from is carried as flat pairs, and the address the edit link on a help callout makes holds a list of values as well, which was handed to the cleaning as though it were a word and ended the request. Such a list is left out now, so every screen reached from a callout can carry a mark of its own.
   3. ✓ Set every mark on the wiki syntax page the same way. A mark named in the middle of a sentence was written bare, so it drew in the body face while the same mark in an example above it drew in a typewriter face. Every such mention is now set the way the page already set a few of them, in a typewriter span, and the two template marks that stood as indented lines are shown in a block like every other example rather than being run as marks. The marks that are meant to run, which show a reader what the syntax produces, are left running. Drawn through the parser before and after: the same nineteen headings and forty-six blocks, with typewriter spans going from two to twenty-seven.
6. Other work accomplished, oldest first. Each step below was reached while working on something else.
   1. ✓ Git clone, push and pull work over HTTP against a Yioop repository. The smart protocol now works over both HTTP/1.1 and HTTP/2.
      1. ✓ Packfiles are built on a fiber. The server answers other requests while one is built.
      2. ✓ Negotiation settles. The server names a commit both sides share, so a client with a long history stops asking.
      3. ✓ A reply states its length and streams. A deferred reply sends only its buffered body, which claimed a length it did not send.
      4. ✓ Only what the client lacks is sent. Objects go as deltas against what it holds. A new GitDelta writes and reads that format on bytes.
      5. ✓ A deep clone of the live repository completes. It stopped partway before, with a differing amount delivered each time.
   2. ✓ A running Yioop keeps its memory bounded. Both servers were made to say where their memory went, and then to use less of it.
      1. ✓ The web server reports its own memory. The request that finally fails is no longer the one blamed.
      2. ✓ The mail server reports its own memory. It had gone from 120MB to its 1GB limit in ten seconds with nothing said.
      3. ✓ A mail server fatal names what it was doing. It gives the account, the folder and the full command, where it named only the bare verb.
      4. ✓ Mail folder indexes are held as plain values. The same folder costs 6MB where it cost 48MB. The cache is bounded by records rather than folder count.
      5. ✓ A web session lives in a file rather than in memory. What the server keeps is the time and use-count. A session past the request-size limit is refused.
   3. ✓ Every page fits its own window. A minimum width on the body container meant pages overflowed between about 601 and 1060 pixels. An activity that is mostly working area now takes the window's width.
   4. ✓ A missing wiki page no longer leaves nulls in the media path. One request raised a warning, a deprecation and a second warning, all from the same defect.
   5. ✓ A visitor can report an issue without an account. The tracker is public to read, so someone who hits a bug no longer has to register or stay silent.
      1. ✓ A report is held for an editor. There is a queue with bulk discard. A reporter may be barred for a week, a month or for good.
      2. ✓ Each repository chooses its own setting. It is none, moderated or unmoderated, defaulting to moderated.
      3. ✓ Issue lists are read by scrolling. Reaching the end fetches the next page as rows. That needed a stable sort order and an allowed offset field.
   6. ✓ Yioop no longer needs three outside programs. qrencode, image magick and calibre were each required for one small thing.
      1. ✓ Yioop draws its own code symbols. The same arithmetic is written in PHP and in the browser. A test compares the two square by square.
      2. ✓ Each kind of file makes its own thumbnail. A document, a book and a text file each do their own, in the processor that owns them.
      3. ✓ Audio messages are transcribed in the browser. The browser listens while a message is recorded. The server keeps nothing beside the recording.
         1. ✓ A recording can become its words before sending. A button beside play and delete replaces the recording with what was heard. The text can be edited and is sent as an ordinary message.
         2. ✓ A recording sent as audio carries its words inside the message. They are its resource description. The pipe and doubled parenthesis are taken out so the words cannot end the markup early.
         3. ✓ The reader's browser draws a toggle that shows the words. It reads them off the page itself, so the click costs no request. Fresh pushed messages get their toggles the same way.
         4. ✓ The send guard resets when a message is sent. It was set once and never let go, so a second message on the same page load was silently held.
   7. ✓ A document thumbnail shows its front page. It reads that page alone, rather than the whole document.
      1. ✓ The page tree is followed to find the first page. That includes reaching through the packed bundles a document may keep its objects in.
      2. ✓ A picture written in the four colors ink uses is read. It is taken apart here, since PHP's own reader returns it as all zeros.
      3. ✓ The page's words are drawn where the page has them. They take the size and color it set, with nothing behind them. Their place is the frame in force when the text began.
      4. ✓ Shapes the page fills are drawn too. That is how a nameplate set as an outline appears rather than being lost.
      5. ✓ A document with a font in it gives up its words. The going back to reading words was compared rather than set. Everything after the first font was skipped.
   8. ✓ A message with a recording sends once and plays on both sides. Sending a recording raised an error and left broken copies, as many as ten. Two halves, both from this afternoon's commits, measured over HTTP/2 against the secure server with a real microphone.
      1. ✓ The lost helper is restored. The GroupModel rewrite dropped linkResourceFolders while newMessage still called it. The Error escaped the route, so the stream was never answered, and the browser resent the same body each time.
      2. ✓ The route accepts the bare token the renderer writes. The renderer had been changed to put the token value alone in a recording's address. The route still demanded name=value or a dash, so every read was turned away to the error page.
   9. ✓ Opening a conversation no longer answers itself with the whole conversation. Every page load sent a call-ended signal, and the reply to it carried the whole conversation back, some six hundred kilobytes a time. Nothing read that reply. Three changes together took the cost to eleven bytes.
      1. ✓ Ending is only said when a call was in progress. Leaving a page said a call had ended whether or not one had begun.
      2. ✓ The event body is read from where the atto server puts it. It had been read from the stream the server leaves empty, so every signal looked like nothing at all.
      3. ✓ A call signal is answered with a small acknowledgment. The sender never reads the reply, so a page is the wrong thing to send back.
      4. ✓ A sent message carries no unnamed parts. Buttons with no name went up with every message and were dropped on arrival.
   10. ✓ A conversation's live channel rides HTTP/2 and sends only new messages. The channel had to fall back to an older connection, and each push carried the whole conversation. It now rides the connection the page already has, and a push is about seven hundred bytes.
       1. ✓ The server offers WebSockets over HTTP/2. It advertises the extended connect setting and accepts the connect that follows, so a socket shares the page's own connection.
       2. ✓ An outbound frame is split to the maximum data-frame size. A frame larger than that broke the connection's framing.
       3. ✓ A push sends the conversation list alone. It had rendered the whole page, so every push carried the chrome around the messages.
       4. ✓ Control frames answered on a socket keep the connection's framing. A close echo written raw corrupted the stream carrying it.
       5. ✓ A carrier stream is let go when its socket closes. It had been held until the stream itself ended, which need never happen.
       6. ✓ A connection carrying a socket still pumps what is waiting. It took a path meant for sockets alone, and a large reply hung.
       7. ✓ A conversation lets go of its channels when the browser leaves the page. Safari otherwise reported the socket closed by suspension.
       8. ✓ A socket is handed what opened it, and touches nothing else of the request. The query and cookies had been put in the arrays an ordinary request uses, where a finished response writes the session named among them.
       9. ✓ How a socket's frames are written is held in place by tests. Seven cases cover the splitting, the wrapping and the drain path.
   11. ✓ A conversation and its contacts can be let go of, in whole or in part. Only the person who wrote a message could remove it, and there was no way to clear a conversation or drop a contact. Each person now manages their own half, and the other keeps theirs.
       1. ✓ Any message in one's own half can be taken off it, whoever wrote it. A message is kept twice, once in each person's group, and only the writer could remove one.
       2. ✓ A whole conversation can be let go. Only that person's copies go; the two remain contacts with an empty conversation between them.
       3. ✓ A contact can be removed from one's own list. Their messages go from this side, along with the row the conversation hung from.
       4. ✓ A contact's row carries three marks that open what can be done. The marks stand at the end of the row and open a list of the two.
          1. ✓ The marks are drawn rather than written as a letter. The letter for them is missing from some of the faces a browser has.
          2. ✓ The row lays its parts out along a line. It had been a plain block, so the marks dropped below the row.
          3. ✓ The words in the list stand in the ordinary flow. The rule placing a contact's name by hand had squashed them.
       5. ✓ The message box fills the width of its panel. A stray closing tag had left the conversation drawn in three panels.
   12. ✓ A recording is made in one kind every browser can play. Each browser writes its own kind and none writes the same one, so a recording made in one played nowhere else. The site now makes every recording over into one kind, written one way.
       1. ✓ The kind asked for is the one the most browsers play. mp4 and mp3 are asked for under every name they go by, by building a recorder with each rather than asking whether it is supported.
       2. ✓ A recording that already arrives in the wanted kind is made over as well. Two browsers writing the same kind do not write it alike.
       3. ✓ Recording is not offered where the site cannot make one over. Without FFMPEG a recording made in one browser could not be played in another.
       4. ✓ A recording carries the mark for its words in the lower corner. It had sat at the top left, over the play controls.
       5. ✓ A recording with no words carries no description, and one is still a recording. It had been given a description naming its own file, and a resource with none was left in the message as plain text.
       6. ✓ A browser that will not listen is not offered the button that asks it to. Only a plain refusal counts as one, since a browser that heard nothing says so with other words.
   13. ✓ Signing out works again. A browser was told the sign-out address had moved for good, so it went straight to where it had been sent once and never signed anyone out again.
       1. ✓ Being sent on is no longer announced as a move for good. A reply carrying only a Location header was answered as moved permanently.
       2. ✓ Signing out empties the request rather than doing away with it. This server keeps its process between requests.
       3. ✓ A failure while a request is handled can be let out rather than caught. Caught, only that connection is let go and the request answers with nothing, which gives little away.
   14. ✓ A wiki page being read names itself on its body. A domain's own stylesheet can reach reading alone, and reach one group or one page within it, without reaching the rest of the site.
       1. ✓ The three classes are read-wiki, the group's name and the page's name. Spaces and underscores become hyphens and anything a class cannot carry is dropped.
       2. ✓ A wiki page served as a static page carries the same classes. The group named is the one the domain routes to, so two domains give two different group classes.
       3. ✓ The class for acting as someone else is gone, along with the rules that waited on it. The name the body looked at was never set anywhere.
   15. ✓ Searching a mail folder lets go of each message once it has been read. The reader that walks a search's terms names itself, and a thing that names itself is not let go when the count of what points at it drops. It held each message body, so a search over a large folder ran the mail server out of memory.
   16. ✓ Tests are kept one class to a file and write under the test files. Cases had been spread across narrow files of their own, and one wrote its scratch work into the work directory.
   17. ✓ A page keeps itself while it is being written. A writer no longer has to remember to save. The page saves itself once they stop typing, and the controls for saving by hand step aside while it does.
       1. ✓ A control beside the editor's other buttons turns the keeping on and off. It is two arrows going round, drawn rather than written. Green says the page is keeping itself, red with a line across says it is not, and the word Saving stands beside it while a save goes.
       2. ✓ Five quiet seconds after a change the page is saved. Nothing further is saved until another change is made. Such a save gives its own reason, so the history reads properly.
       3. ✓ The controls for saving by hand step aside while the page keeps itself. The reason for an edit, the save button and the way to see the page are left out. A page's settings are a form to fill in and send, so they keep their save button and are never offered the keeping.
       4. ✓ Each save takes the fresh mark the site sends back. A save whose mark is older than the page's last change is refused. Without this the first save of a sitting landed and every one after was turned away.
       5. ✓ A file dropped into the writing area is sent at once. Its name went into the page while the file waited for a press of save that never came. The writer stays where they were while it goes, and the count of how much has gone up is cleared when it lands.
       6. ✓ A page written for the first time learns its own name. Such a page has no id until it is saved, and a page that saves itself never reloads. The id is taken from what the site sends back, so the preview can ask for the files kept with it.
   18. ✓ The preview reads a page the way the site will. A writer sees what a reader will see rather than an approximation. Each piece was built by rendering samples through the site and matching them.
       1. ✓ A page written in markdown has a preview of its own. There was a reader for wiki markup and none for markdown. The new one covers words, headings of both kinds, lists, quotations, rules, code, tables, links, notes and the marks that work within a line.
       2. ✓ Both readers take the templates that name a class, an id or a style. Only the plain names were read, so a page using the block forms lost its wrapping. A template laid out over several lines is read too, on the site as well as in the browser.
       3. ✓ A block written with quotes reads the same after a save. Text is cleaned on its way in, and cleaning turns a quote into the name standing for it. Both marks now open a value, so a block survives the round trip.
       4. ✓ Both previews draw the fields of a form. A page showed the words asking for a field rather than the field. One drawer serves both readers and covers every kind the site knows.
       5. ✓ A form looks as it will to a reader. The site leaves standing-in marks and fills them when it draws a page, so the preview showed them as words. A fresh form now comes up empty, and the date rides along without being shown.
       6. ✓ A list carries its choices and a field keeps the words after it. A list takes its choices from a block named beside it, which the preview never copied. A field followed by anything on the same line was left unread.
       7. ✓ The preview is dressed the way a reader will see the page. It carries the same three classes a page being read carries. A domain's own stylesheet reaches what the writer is looking at.
   19. ✓ Files kept with a page draw in the preview. A picture, a document or a recording named on a page shows as itself. The address it is asked for at is built the way the site builds it.
       1. ✓ A file is asked for the way the site serves it. Where the site serves pretty addresses it serves a file as a path rather than a query. The address is rooted at the site, since a path read against the page points under that page.
       2. ✓ A file is asked for under the mark the site would use. A file belonging to the public group, or to any group anyone may join, is asked for under a row of zeros. The page works this out as the site does and tells the preview.
       3. ✓ Every kind of picture the site serves is drawn. The list of picture endings was written before webp and the kinds that followed it. A picture asked for without a link is drawn on its own, and a document is shown in a frame.
       4. ✓ A file asked for as a thumb draws the small picture kept beside it. The reader drew the file itself, which for a document meant a bare link. The site draws it the same way now, and neither points at a picture that was never made.
       5. ✓ A file named inside a table cell stays whole. Such a naming carries a bar of its own, and a bar ends a cell. The reader follows the depth of a naming as it already followed a link's.
       6. ✓ A file added to a page is described with a space before its name. The word and the name ran together.
   20. ✓ A page carries its locale wherever it goes. A writer works on a page in one language while reading the site in another. Every way of looking at the page stays in the language being worked on.
       1. ✓ A writer chooses which locale a page is written in. The locale above the editor was a word; it is a choice now. Choosing another goes to that locale's page, so what is saved after goes there.
       2. ✓ The locale goes with every way of looking at a page. Reading a page's history, its source or its editor fell back to the reader's own language. It travels on the row of activities and on the links the page draws.
       3. ✓ Reverting goes back to the history, in the locale it was read in. A revert wrote the old words into the reader's locale rather than the version's. The way out afterwards led to the group's talk rather than the history.
       4. ✓ A locale is named by its language wherever it is shown. The history and the message about a group having no pages gave the tag. They now read as the edit page has always read.
       5. ✓ A page's history carries a way back to it. Reading the history left no way out but the browser's own back. A close mark stands beside the button that asks for a difference.
   21. ✓ The scripts are named for what they hold. help.js was mostly a reader of wiki markup. The reading now lives in wiki_parser.js, the preview machinery in editor.js, and markdown_parser.js reads markdown. Everything that includes or names them moved with them.
   22. ✓ A message naming a character set the machine has never heard of no longer stops the mail server. A subject written in windows-1250 was handed straight to the converter, which raises an error rather than reporting a failure. The conversion is attempted and any error caught, another way is tried, and text that cannot be converted is kept as it came.
   23. ✓ A pull of the live repository completes. Cloning worked while pulling did not, in a different way each round. A pull now finishes against the repository the site itself is served from. Each fault was a way of doing too much at once. A whole pack in memory, a whole history walked, a whole chain of differences held. The parts below are those, oldest first.
       1. ✓ Serving a pull no longer holds the whole site. One pull ran for two minutes with nothing else answered. Building a pack walks history and works out differences, a long stretch with no waiting in it. The service runs inside a fiber and hands the loop back between objects. A task carries its own running-time limit, since the page-rendering one cut the pull short.
       2. ✓ A pack is built into a file rather than in memory. Holding every object exhausted two gigabytes on a repository of any size. The reply is built into a scratch file that spills to disk. The server drains it a piece at a time. A failure part way through is now an error the other side can see.
       3. ✓ A repository holding a large file can be cloned. An object was refused past sixty-four megabytes, so a project holding a larger one could not be cloned. The ceiling is five hundred and twelve megabytes now. A very large object is sent whole, since comparing two such objects holds both.
       4. ✓ A long chain of differences is read one step at a time. A chain ran to a thousand steps, each holding its difference while the version below was read. The version below is read first and the difference unpacked after. The chain is followed no further than git itself writes.
       5. ✓ A client's lines are read only as far as they go. Reading carried on past the last line into what followed, which in a push is the pack. Those bytes went to a hexadecimal reading that took whichever characters were valid. Anything that is not a length now ends the reading.
       6. ✓ A pull stops where the two sides' histories meet. Only the commit a client named was marked as reached, not the ones before it. So a commit off the path being walked stopped nothing. The whole repository was gathered for a pull of a few objects. The client's own history is walked first, commits alone, costing a fraction of a millisecond each. On a branch that left the trunk forty commits back, the walk now gathers what git names.
       7. ✓ A request and a failed reply both say what they were. A build that failed left no headers, no body and nothing in any log. Several rounds of chasing it had no evidence to work from. A switch records each request's length, first bytes and encoding, and what was built in answer. A build that throws is recorded with the object it failed on and answered with the reason.
   24. ✓ The search bar and the results share the reading column's measure. The bar stood twice as tall as it should on a wide window. It and the count of results ran to the window's edge. Both now end where the reading column ends. That measure is named once and shared. Right edges line up rather than drifting apart as a window widens.
       1. ✓ The search bar beside the logo is one line again. Its field had a width of its own, leaving too little room beside it. The two buttons were sent onto a second line. The field takes whatever room is left now, which keeps the bar one line at any width. The logo and the bar sit side by side as a row. Before, one was lifted by a fixed amount to appear beside the other.
       2. ✓ The panel beside the results moves into the column when it cannot fit. Kept beside the results it lay over the advertisement, the count and the results themselves. Below the width where column and panel cannot both fit, the panel is carried into the column. The one panel is moved rather than a second drawn, so the page says each thing once.
   25. ✓ A group sets a theme, header and footer for all its pages. Each page had to be set by hand, so a group of any size drifted apart. A group now holds all three for a page that sets none of its own, and can say whether a page may set its own at all; where it may not, the controls are not offered. Its settings screen is grouped into Organization, Membership, Appearance, Feeds and Wiki, each with its own help.
   26. ✓ A writer can keep several lines together where only one line was allowed. The meaning beside a term in a definition list ended at its line, so a list or a second paragraph could not go inside one. A same-unit mark now holds as many lines as are wanted. Markdown gained definition lists at the same time, having had none.
   27. ✓ A writer can put in any markup without remembering how it is spelt. The row of marks above the writing area covers what is reached for most, and everything else had to be typed from memory or looked up on the syntax page. A mark beside the search one opens a list of the rest, and choosing a line puts that markup in where the writer was, with an example in each part it takes. The list scrolls, so it does not push the writing area off the screen.
   28. ✓ Markup shown as an example stays as it was typed. The page parser broke the double brace in text kept verbatim. A front page mark shown inside nowiki came out altered rather than as written. Those marks are read while the page is scanned now, so one inside nowiki never becomes a mark. The browser parser never broke it, so the two read the same page differently until this.
   29. ✓ The screen that starts a secret ballot draws again. It answered with an Internal Server Error. Two helpers named the ballot's secrets file while their bodies read the file a round waits in. Both take the round's file now, and the model names that file the same way throughout. Writing to a path left undefined raised a ValueError that nothing caught.
   30. ✓ A user can be saved from the Manage Users screen again. Both password boxes arrive holding a stand-in for a password nobody is changing. The browser judged it, said an upper-case letter was missing, and held the whole form back. Such a box now carries a mark saying what it holds, and is left alone until somebody types in it. A password typed there is still held back while it breaks a rule.
   31. ✓ A site sends its own mail without its mail server running. The checkbox that says to do so read MailSite Handled, which told a reader nothing about what had to be turned on. It reads Use Built-in SMTP Client now, and with it on a message goes to this machine's mail server where mail services are turned on here and to each recipient's own mail server where they are not. A site with them off makes no connection to itself at all. With it off, the fields naming somebody else's mail server are shown and used, as before. The carrying to a recipient's server was written twice and is now written once. A site with no submission port written down falls back to the standard one, since a port of nothing makes an address nothing can be reached at. Where a message goes at once and where it waits for the media updater is settled by Use a Queue alone, invitations to witness a ballot included.
   32. ✓ The settings for sending mail sit with the other mail settings. They were in the Account Registration box on User, Roles, Groups, hidden whenever registration wanted no mail, so an operator could not find them. They are a System Emails box on Server Activity now, above Mail Services, and Account Registration holds only its dropdown. The Mail Services banner goes away with the rest when mail is disabled, where before it stayed on its own. Their names begin with servers element and read from their English: sender email, smtp server, server port, use a queue. Translations already written moved with them across twenty-five languages.