Skip to content

Keep the final code in the local history - #321

Merged
jserv merged 1 commit into
sysprog21:mainfrom
Patriciaath999:keep-final-code
Oct 25, 2026
Merged

jserv merged 1 commit into
sysprog21:mainfrom
Patriciaath999:keep-final-code

Conversation

@Patriciaath999

@Patriciaath999 Patriciaath999 commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

A report reopened from Past attempts always shows "(final code was not saved)", on the page and in its .md download, even for the attempt just finished. saveHistory never put the editor contents in the history entry, and normalizeProgressEntry would have dropped them before the lobby saw them.

  • saveHistory adds code to the entry: the editor contents, or null at a whiteboard, which has no code.
  • The short history (codetrial_history, newest 20) keeps it. boundedReviews strips it, so the review store is byte for byte what it was and its 164 KB budget holds as many older attempts as before. Attempts older than the newest 20 keep the placeholder.
  • When the quota refuses the short history, or the review store write that follows it, saveLocalReport writes the history again with the older rows' code left out, then without this report's own, retrying the review store each time, so the attempt just finished keeps its code longest and the code never costs an attempt the device would otherwise keep. When no step lets the review store in, the refusal was not the code's, and the history goes back to the step it first landed at.
  • saveHistory adds the code after withUnclearLines has bounded the unclear lines, since that bound is the account body's and the account copy never carries the code, so a long solution does not cost the attempt its unclear lines.
  • The /api/reports body leaves code out, since the server stores that body as sent. A signed-in lobby fills it in by report id from this device's history (withLocalCode in renderServerHistory), so the code shows wherever the device has it, without changing the server body.
  • normalizeProgressEntry carries code as a string or null, and the reopened report and its download use it, falling back to the placeholder when it is null.
  • README.md says the browser keeps the final code of up to its 20 newest attempts in local storage, that the account copy never carries it, and that deleting an attempt removes it.

Validation on Windows 11, Node, Playwright Chromium, rebased on main at 6b739c5:

  • New tests: a saved entry carries the code, a whiteboard entry does not, and a long code keeps every unclear line (interview-lifecycle.test.js); the short history keeps it while the review store and the account request body are identical to a save without code, a stored __proto__ field survives the copy, a quota-limited storage still saves every attempt, keeps each new report's own code and drops the oldest code first, a review store that would not fit beside a history full of code still keeps every attempt, a review store that refuses every write leaves each attempt its code, and account rows take the code this device kept by report id (account.test.js); normalizeProgressEntry keeps only a string (progress.test.js); device and account attempts reopen with the code this device kept, on the page and in the download, and one without code still shows the placeholder (lobby.test.js). Each was seen to fail with the behavior it covers broken, twenty-eight breaks in all, and pass once restored.
  • node --test tests/browser/*.test.js: 112 failures on this branch and the same 112 by name on main at 6b739c5, from vendored assets not fetched on this machine and from the lobby fits on one screen instead of a wall of problems, which measures 802px against 800px here on both. The branch adds 10 tests, all passing.
  • ESLint and Prettier pass on the changed files; README.md's only Prettier difference is in its tables, as on main.
  • Not run here: scripts/test.sh as a whole, including the Rust lanes, which need a toolchain this machine does not have. No Rust file changed.

Closes #221

cubic-dev-ai[bot]

This comment was marked as resolved.

Comment thread web/interview.js Outdated
Comment thread web/interview.js Outdated
Comment thread web/history.js
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(entry),
body: JSON.stringify(withoutCode(entry)),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving code out of the account body is consistent with what the description says, but it means a signed-in candidate sees the placeholder even on the device that holds the code: renderServerHistory never looks at local storage. A follow-up could fill in code from readLocalHistory() by id before showProgress. That shows the code wherever the device has it, without touching the server body or the open question on #221.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Included here rather than as a follow-up: renderServerHistory passes the account rows through withLocalCode (web/history.js), which fills code in by report id from this device's history. The server body is unchanged, and the lobby test covers a signed-in candidate.

jserv pushed a commit that referenced this pull request Oct 16, 2026
"disabled execution hides the test drawer divider" read isHidden() once
right after DOMContentLoaded. The page hides the divider and the drawer
in init(), which runs only after interview.js finishes its top-level
await on the problem fetch, and DOMContentLoaded does not wait for that.
On a loaded runner the read lands first and sees the divider still
visible; this failed once in CI on #321 while passing locally and on
main. Wait for both elements to become hidden instead. With the problem
fetch delayed by 1.5 s, the old read fails with the same "actual: false"
and the wait passes.

@jserv jserv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid ambiguous Refs #221.
The goal should be "Close #221."

Comment thread web/history.js Outdated
jserv

This comment was marked as outdated.

jserv

This comment was marked as outdated.

Comment thread web/history.js Outdated

@jserv jserv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before asking someone to review, you MUST resolve any regressions flagged by GitHub Actions.

Comment thread web/history.js Outdated

@jserv jserv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rebase latest main branch and explain how the CI result changes.

The gates (browser) failure here is Strict delayed judge language restoration respects end in tests/browser/strict-selection.test.js. This branch did not break it: the test was flaky on main itself. After End it waited for the ending overlay, but its room has no interviewer, so the offline summary replaced that overlay a moment later and a loaded runner missed the window. #461 (merge b0059b2) fixed the test by pausing a fake clock before End, and main passes the browser lane again at that commit. This branch is based on a commit before b0059b2, so it still runs the old test. After rebasing, reply here with the new CI result, and if anything still fails, say whether it comes from this branch or also fails on main.

The same lane also fails the lobby fits on one screen instead of a wall of problems, which passes on main, so that one comes from this branch and a rebase alone will not clear it.

@jserv jserv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rebase latest main branch and resolve conflicts.

@jserv

jserv commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Add screenshots to the pull request description to illustrate your work, as @ColtenOuO suggests. Example: #349

A report reopened from Past attempts always showed "(final code was
not saved)", on the page and in its download. saveHistory never put
the editor contents in the history entry, and normalizeProgressEntry
would have dropped them before the lobby saw them.

The entry now carries the code, or null at a whiteboard, which has
none, and the reopened report and its download use it. It joins the
entry after the unclear lines are bounded, since that bound is the
account body's and the account copy never carries the code. Only the
short history of the newest 20 attempts keeps it: the review store
is built without it, so its 164 KB budget holds as many older
attempts as before, and those keep the placeholder. When the quota
refuses the history, or the review store write that follows it, the
history is written again with the older rows' code left out, then
without this report's own, so the attempt just finished keeps its
code longest and the code never costs an attempt the device would
keep. When no step lets the review store in, the refusal was not the
code's, and the history goes back to the step it first landed at. The
/api/reports body leaves it out, since the server keeps that body as
sent; a signed-in lobby fills it in by report id from this device's
history instead. README.md says the browser keeps it.

Closes sysprog21#221

Co-Authored-By: Fang-Yu Zhang <nancy99b@gmail.com>
@jserv
jserv merged commit 4afb576 into sysprog21:main Oct 25, 2026
11 checks passed
@jserv

jserv commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Thank @Patriciaath999 for contributing!

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.

Final submitted code is not preserved in Past attempts reports

2 participants