Skip to content

Let candidates lead the Algorithm and Coding steps - #462

Merged
jserv merged 1 commit into
sysprog21:mainfrom
Jerry-Chiang-23:candidate-led-coding
Oct 25, 2026
Merged

jserv merged 1 commit into
sysprog21:mainfrom
Jerry-Chiang-23:candidate-led-coding

Conversation

@Jerry-Chiang-23

@Jerry-Chiang-23 Jerry-Chiang-23 commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Jim always volunteers the next step once a candidate stalls during Algorithm or Coding, even for interviewers who expect the candidate to lead those two steps themselves.

Add a candidate-led toggle: a lobby checkbox carried through participant metadata to a new prompt policy scoped to the Algorithm and Coding steps only. Enabled, Jim asks an open question and waits for the candidate to state the next step instead of proposing one; Repeat, Example, Test and Optimizations are unchanged.

This is a live-prompt policy change, so it bumps LIVE_PROMPT_VERSION and INTERVIEW_CONTRACT_BUNDLE_VERSION to 32 and 41, refreshes the prompt golden's recorded digest, and adds a row to docs/interview-contract-versions.md.

Closes #115


Summary by cubic

Lets candidates lead the Algorithm and Coding steps during their interview. Jim previously always volunteered the next step when a candidate stalled during those two steps; with a new lobby checkbox, interviewers can opt the candidate in, and Jim instead asks an open question and waits for the candidate to state the next step.

  • Carries the toggle through participant metadata into a new live-prompt policy scoped to Algorithm and Coding only; Repeat, Example, Test, and Optimizations are unchanged.
  • Bumps the live prompt to version 32 and the interview contract bundle to 41, and refreshes the prompt golden.

Screenshot: the new lobby checkbox.
image

Closes #115.

Written for commit 1dd3254. Summary will update on new commits.

View guided diff

Comment thread src/agent/prompts.rs Outdated
Comment thread src/agent/prompts.rs Outdated
Comment thread src/web/token.rs
.expect("metadata is an object")
.insert("codeExecution".to_string(), Value::Bool(false));
}
if request.get("candidateLed") == Some(&Value::Bool(true)) {

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.

Nothing tests this path. candidateLedInstructions calls the prompt builder directly, so if the flag is dropped anywhere between the lobby, the token request, the signed metadata and parse_participant_metadata, everything stays green and the checkbox does nothing. Copy the exampleDrawing cases already in tests/web/token.rs (literal true kept; false, "true" and 1 dropped), tests/runtime.rs and tests/browser/lobby.test.js.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added tests/web/token.rs::token_carries_candidate_led_only_when_true, tests/runtime.rs::candidate_led_is_explicit_in_both_modes, and three lobby.test.js cases, mirroring the exampleDrawing coverage.

Comment thread src/agent/prompts.rs Outdated
Comment thread src/agent/prompts.rs
fn candidate_led_nudge(enabled: bool) -> &'static str {
if enabled {
" If this stall is in the Algorithm or Coding step, ask what they are \
thinking of doing next without naming or steering toward one yourself, and \

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.

When Repeat, Example and Algorithm are all recorded and the editor is untouched, silence_nudge already says "ask them to begin writing their code in the editor.", and this sentence is added after it in the same event. So during Coding the model gets two instructions at once: name the next step, and don't name or steer toward one. When candidate_led_enabled is set, pick the open question instead of the unwritten branch rather than appending to it. Add a golden case for that state as well: silenceCandidateLed uses a default RuntimeState with no steps recorded, so it never reaches this conflict.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

When Repeat and Example are both recorded and the editor is untouched, silence_nudge now substitutes the open question for naming the next step instead of appending it after; the hedged candidate_led_nudge wording is kept only for the states where Rust can't tell the current step from RuntimeState alone (code already written, so the stall could be in Coding, Test, or Optimizations). Added silenceCandidateLedBeforeCoding, a golden case that hits exactly the state you named.

@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.

Comment thread src/agent/prompts.rs Outdated
Comment thread docs/interview-contract-versions.md Outdated
@Jerry-Chiang-23

Copy link
Copy Markdown
Contributor Author

Rebased onto main and resolved the conflicts from the Pause-removal PR taking bundle 40/live prompt 31; this branch is now clean against main.

Comment thread src/livekit.rs
interview_mode: boot.interview_mode,
code_execution_disabled: boot.code_execution_disabled,
example_drawing_enabled: boot.example_drawing_enabled,
candidate_led_enabled: boot.candidate_led_enabled,

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.

Nothing tests that this assignment and the one in candidate_bootstrap carry the setting into RuntimeState. The new test in tests/runtime.rs calls bootstrap_with_rounds directly, and the token tests stop at parse_participant_metadata. If either line is dropped, the suite still passes, yet opted-in candidates get the ordinary silence nudges. tests/unit/livekit.rs already checks example drawing this way (candidate_bootstrap then initial_runtime_state, asserting state.example_drawing_enabled). Add candidateLed true, false and absent to that test, or add a test beside it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added candidate_led_initial_state_carries_signed_choice beside the example drawing test, calling candidate_bootstrap then initial_runtime_state with candidateLed true, false and absent across both modes.

Comment thread tests/agent.rs Outdated
@jserv

jserv commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

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

@jserv
jserv requested review from ColtenOuO and alanhc October 24, 2026 14:54

@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.

Comment thread src/agent/prompts.rs
// the open question in place of `unwritten` instead of appending it, and
// the trailing append below is skipped only in that same untouched-editor
// state, where it would otherwise double up on the substituted text.
let candidate_led_certain = state.candidate_led_enabled

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.

phases_evidenced only says some non-skipped Repeat and Example evidence exists. It does not say the candidate has left Example. Take a candidate who walks through the ordinary case, gets an Example entry, and then stalls before the boundary case with the editor untouched. candidate_led_certain is true, so the nudge swaps "ask for whichever of their understanding, example, or planned algorithm they have not explained" for the open "what next" question and also drops the hedged clause. That changes Example, which the description promises stays the same. The same happens when a candidate goes back to Example after starting Algorithm. Add Algorithm to the check (Repeat, Example and Algorithm all evidenced, editor untouched, means the stall is in Coding) or keep the hedged form here, and add a test with only Repeat and Example recorded while the conversation is still in Example.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added Algorithm to the check: candidate_led_certain now requires Repeat, Example and Algorithm all evidenced, matching what unwritten itself requires, so the open question only replaces the hedged wording once the stall is certainly in Coding. With only Repeat and Example recorded the hedged form still runs, covering a candidate back in Example or about to start Algorithm. Added silenceCandidateLedInExample, a golden case with only Repeat and Example recorded, and renamed silenceCandidateLedBeforeCoding's evidence to add Algorithm so it still hits the certain case.

@Jerry-Chiang-23

Copy link
Copy Markdown
Contributor Author

Added a screenshot of the new checkbox to the description.

@Jerry-Chiang-23

Copy link
Copy Markdown
Contributor Author

Squashed the fixup! commits into one (git rebase -i, git reset --soft) and rebased onto main, which now carries #473. The single commit follows Chris Beams' rules: imperative, capitalized, 50-char subject, blank line, body under 72 columns explaining what and why. Ran install-git-hooks.sh to pick up the updated commit-msg hook and confirmed it passes locally before pushing.

@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.

Remove AI markers such as Co-Authored-By:.

@Jerry-Chiang-23

Copy link
Copy Markdown
Contributor Author

Removed the Co-Authored-By: trailer and amended the commit (4ddbd97, force-pushed). Diffed the amended tree against the previous commit — it's empty, so only the message changed, no code moved. Also scanned the full diff for any other AI markers (co-authored-by, generated with, etc.); none found elsewhere in the code, docs, or tests.

Comment thread src/agent/prompts.rs
} else {
format!(" They have not written code yet: {unwritten}")
}
} else if candidate_led_certain {

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.

The arm for an editor that was touched but not written (If the editor holds none of their code, ... Otherwise: {with_code}) has no case in tests/golden/prompts.json: silenceCandidateLedWriting is the written arm and silenceCandidateLedBeforeCoding the untouched one. Replacing this arm with the plain unwritten text leaves the suite green. Add a case with Repeat, Example and Algorithm recorded and code that differs from the starter but is not counted as written.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added silenceCandidateLedTouchedNotWritten: Repeat, Example and Algorithm recorded, the editor one character over the starter (too little to count as written). Also fixed the same evidence-vs-active-step gap you flagged below in this branch, not just the untouched one, so its text leads with the scoped "if this stall is in the Algorithm or Coding step" clause too instead of the plain open question.

Comment thread web/styles.css Outdated
Comment thread src/agent/prompts.rs
// appending it, and the trailing append below is skipped only in that same
// untouched-editor state, where it would otherwise double up on the
// substituted text.
let candidate_led_certain = state.candidate_led_enabled

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.

candidate_led_certain treats "Repeat, Example and Algorithm have evidence and the editor is untouched" as proof the stall is in Coding, but phases_evidenced checks accumulated evidence, not the active step. A candidate who goes back to Example with a concrete concern before writing code still satisfies it, so the nudge swaps in the candidate-led open question and drops the hedged unwritten wording. That applies the new policy during Example, which the bundle 41 entry says is unchanged. Keep the "if this stall is in the Algorithm or Coding step" scope on this branch unless the active step is known independently, and add a golden case for a return to Example after all three phases are recorded.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed, and fixed: this branch (and the touched-but-not-written one below it) no longer substitutes the open question outright. Both now lead with "if this stall is in the Algorithm or Coding step, {open question} Otherwise, {the usual unwritten/with_code text}", so a return to Example gets exactly the wording it would without candidate-led enabled. Added silenceCandidateLedReturnedToExample: same evidence as silenceCandidateLedBeforeCoding plus a second Example entry recorded after Algorithm, asserting the identical (correct, scoped) output text.

Comment thread web/styles.css Outdated
Jim always volunteers the next step once a candidate stalls during
Algorithm or Coding, even for interviewers who expect the candidate
to lead those two steps themselves. Add a candidate-led toggle,
carried from a lobby checkbox through participant metadata to a new
prompt policy scoped to those two REACTO steps only: enabled, Jim
asks an open question and waits for the candidate to state the next
step instead of proposing one. Once Repeat, Example and Algorithm
are all evidenced, the nudge leads with that question scoped to "if
this stall is in the Algorithm or Coding step", folding the usual
next-step text into the same conditional as its "otherwise" rather
than naming it outright: accumulated evidence cannot prove the live
conversation has left Example for good, so a candidate who returns
to it before touching the editor gets the wording unchanged. The
other four steps are unchanged. Bumps LIVE_PROMPT_VERSION and
INTERVIEW_CONTRACT_BUNDLE_VERSION to 32 and 41, and refreshes the
prompt golden.

The lobby's new row needs headroom on the one-screen laptop
breakpoint; the shared caption padding and checkbox min-height stay
untouched; margins on the hero and header already scoped to that
breakpoint give the row back its room instead.

Closes sysprog21#115
Comment thread src/agent.rs
Comment on lines +183 to +184
pub const INTERVIEW_CONTRACT_BUNDLE_VERSION: u32 = 41;
pub const LIVE_PROMPT_VERSION: u32 = 32;

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.

The PR description says this bumps LIVE_PROMPT_VERSION and INTERVIEW_CONTRACT_BUNDLE_VERSION to 31 and 40, but the diff moves them from 31 and 40 to 32 and 41 (and the docs row and golden digest agree with 32 and 41). Update the description so it matches what merges.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch — updated the description's two mentions (the main paragraph and cubic's auto-generated summary) from 31/40 to 32/41, matching the diff, the docs row, and the golden digest.

@jserv
jserv merged commit 513f68b into sysprog21:main Oct 25, 2026
11 checks passed
@jserv

jserv commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Thank @Jerry-Chiang-23 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.

Allow users to select Jim's guidance level before interview

2 participants