DEV Community

khwaja mohiddin
khwaja mohiddin

Posted on

Designing a Review Interface That Shows Hindsight Memory Working

Memory you cannot see is memory nobody believes. Our review agent stores every Accept and Reject in Hindsight, so the interface had one job: make that memory visible within a minute of using it. This article covers the design choices, one before and after from the screen, and the limits.

What the agent needs from a person

The Review Desk reads a pull request diff and posts comments inline, under the lines they refer to. Each comment needs a decision from a person: Accept or Reject, with an optional reason. The reasons are limited to three allowed values, which keeps what we store tidy. Every decision goes into Hindsight, and the agent recalls those decisions before the next review.

The Review page with inline comments and Accept / Reject buttons

Making the decision fast

A reviewer makes dozens of decisions, so the hands should stay on the keyboard. The shortcuts are J and K to move between comments, A to accept, R to reject, 1, 2 and 3 to pick a reason, and Esc to cancel. They are printed under the comment list, so nobody has to find them.

This is the real code that handles the keys:

    const f=e=>{
      if(e.ctrlKey||e.metaKey||e.altKey||/INPUT|TEXTAREA/.test(e.target.tagName))return;
      const k=e.key.toLowerCase(),i=Math.max(0,notes.findIndex(c=>c.id===act)),c=notes[i];
      if(rej){const rc=notes.find(x=>x.id===rej);
        if(k==="escape")setRej(null);else if(rc&&["1","2","3"].includes(k))vote(rc,"reject",REASONS[+k-1]);return}
      if(k==="j")go(i+1);else if(k==="k")go(i-1);
      else if(c&&!done[c.id]){if(k==="a")vote(c,"accept","");else if(k==="r")setRej(c.id)}};
    window.addEventListener("keydown",f);return()=>window.removeEventListener("keydown",f)```



## Showing what memory did

There are three places where memory shows up on screen.

**The Learned conventions panel.** Each rule reads like "Stop flagging docs comments" or "Keep flagging security issues", with counts such as "0 accepted, 1 rejected" underneath and a Stop or Keep label on the right.

**The recalled notes.** Above the comments there is a dropdown, "Recalled for this review", with a count. It lists the notes recalled from Hindsight before the review ran, so a person can see what the agent was told.

**The Replay page.** It replays 21 real Flask pull requests in merge order. Each block is one review comment, and it is either accepted, rejected for the first time, or rejected again. The row without memory ends at 62 repeated rejections, 96 comments and 29 accepted. The row with memory ends at 0, 47 and 39. The page carries a line saying every block comes from the measured replay.

A concrete example from the replay is pull request #6133, "add `app.query` route decorator". Without memory the agent wrote 6 comments and 3 of them were repeated rejections. With memory it wrote 2 comments and none were repeated.

## A before and after from one session

Before I clicked anything in a test session, the Learned conventions panel held five rules: four Stop rules (debug print, docs, typing, style naming) and one Keep rule (security). I then rejected two comments. The panel grew to seven rules, with two new Stop rules added, one for "other" and one for "bug", each showing "0 accepted, 1 rejected".

One caution: those two rules came from my own test clicks. They are not part of the measured replay, and a bug rule like that is the opposite of what the scripted team in the replay does.

![A rejected comment marked as remembered, with the ten-second settling notice]
(https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/4r1dllss672m9x0cd6dr.png)

## The ten-second problem

Hindsight needs about ten seconds to process a retain. If a person rejects a comment and starts the next review straight away, the recall will not include that decision yet, and it will look like memory failed. So after a rejection the page shows a "Rejected, and remembered" message and a line saying memory needs about ten seconds to settle before the next review. I would rather show a small delay than let a normal delay look like a bug.

## Visual choices

We kept the style plain on purpose. It is a dark theme with muted green text, two fonts (Press Start 2P and VT323), square corners, and no gradients, shadows, icons or emojis. Motion happens only on load, on scroll and when the data changes, and there is a fallback for people who ask their system to reduce motion. Loading states use skeleton loaders. There are real Terms and Privacy dialogs, because a demo without them looks unfinished.

The whole frontend is one file of React loaded from a CDN, with hash routing between five pages: Review, Conventions, Results, Replay and How it works. There is no Node build step. The cost is a console warning that Babel is running in the browser. The scripts from the CDN also trigger "Tracking Prevention" lines in Edge, which are harmless.

![The Results graph: repeated rejections as memory builds]
(https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/mxcaetzkk5o3k583mfux.png)

## Limits

* Inline placement of comments is approximate.
* The comments are unverified model output. At least one security comment about the Host header is a stretch, and none are confirmed Flask bugs.
* The interface shows comments. It does not post them back to the pull request on GitHub.
* The paste-a-PR-link box works on localhost only. The public link is read-only.
* The replay used a scripted reviewer and one run per arm.
* Decisions are stored in a plain text file with no encryption at rest.

## Takeaways

1. Put the memory on screen. A panel of learned rules did more to explain the agent than any paragraph.
2. Tell people about delays in the place where the delay happens.
3. Keep the keyboard path complete. Review is repetitive work.
4. Show a real replay, and say that it is real.

## Try it

The code is at [github.com/abhiram0411/review-desk](https://github.com/abhiram0411/review-desk). A read-only copy is at [review-desk-z659.onrender.com](https://review-desk-z659.onrender.com), and the first load can take a minute or two because it is on a free host. The [Hindsight docs](https://hindsight.vectorize.io/) cover retain and recall, and the [agent memory page on Vectorize](https://vectorize.io/what-is-agent-memory) explains the idea behind it.

Tagging [Code.in](https://code.in/).

Enter fullscreen mode Exit fullscreen mode

Top comments (0)