Skip to content

requireFullTime -> timeMinimumInMinutes#1059

Open
rasmi wants to merge 9 commits intoPAIR-code:mainfrom
rasmi:min-time-clean
Open

requireFullTime -> timeMinimumInMinutes#1059
rasmi wants to merge 9 commits intoPAIR-code:mainfrom
rasmi:min-time-clean

Conversation

@rasmi
Copy link
Copy Markdown
Collaborator

@rasmi rasmi commented Mar 17, 2026

  • Rename requireFullTime (boolean) to timeMinimumInMinutes (number | null), allowing experimenters to set a specific minimum time independent of the max time limit.
  • Add enforcement of timeLimitInMinutes in private chat (previously only enforced in group chat).
  • Add server-side validation of minimum time requirement in chat.utils.ts and chat.endpoints.ts.
  • Add migration script to convert existing requireFullTime: true stages to equivalent timeMinimumInMinutes values.
  • Force integer values for time inputs in editors.
  • Add server-side validation between parameters

(in lieu of #1058).

@rasmi rasmi requested a review from cjqian March 17, 2026 19:42
if (!this.stage) return;
const val = Number((e.target as HTMLInputElement).value);
const max = this.stage.timeLimitInMinutes;
const clamped = max !== null ? Math.min(val, max) : val;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If I'm reading this right, the form and value representation will both accept Numbers (including floats?), but the actual time comparison only compares based on an integer number of minutes. If someone enters in a time limit of 2.5 minutes, will we happily claim to have accepted it, and then actually do a limit of 3 minutes in practice?

Normally I'd suggest storing this as seconds internally, partially to make that clearer and partially because it's more common to store times that way IME (so less surprising). But we do already store the time limit in minutes.

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.

Added a TODO for the seconds switch (and enforced setting ints in the UI in the meantime)

Elapsed time from first message to conversation close (in
minutes)
</label>
<label for="timeLimit"> Maximum time (in minutes) </label>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This wording makes it less clear when we start measuring time. If I were reading this in a vacuum, I'd assume it meant maximum time since the stage became available.

Maybe something like "Maximum time in minutes (starting at first message)"?

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.

Done.

elapsedMinutes >= this.stage.timeLimitInMinutes;

// Check if conversation has ended
const isConversationOver = maxTurnsReached || maxTimeReached;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The PR description only mentions changing the minimum time config, but this looks like it's changing something around how the end of the conversation is determined. Does it, and if so can you mention in the description?

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.

Done.

(discussionStartTimestamp !== null &&
elapsedMinutes >= this.stage.timeMinimumInMinutes);

const isNextDisabled = !minTurnsMet || !minTimeMet;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe a preexisting issue, but what happens if max time elapses before min turns? Will chat get stuck with no way to advance or send new messages?

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.

@cjqian and I discussed and we decided to enforce min requirements over max requirements (i.e. must hit min turns regardless of max time, and same for min_time / max_turns). Noted in the editor UI as well.

return html`
<div class="description">
You must stay on this chat for at least
${this.stage?.timeMinimumInMinutes} minutes.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Would it be easy to give an indication of how much time is left here?

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.

Done.

timeLimitInMinutes: Type.Union([Type.Number(), Type.Null()]),
requireFullTime: Type.Union([Type.Boolean(), Type.Null()]),
timeMinimumInMinutes: Type.Optional(
Type.Union([Type.Number(), Type.Null()]),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I see we have client-side validation that minimum is between 0 and maximum, but nothing server-side. Can we add that? Ideally we'd have both validation checking that here, and something to make sure the API rejects attempts to set it.

Copy link
Copy Markdown
Collaborator Author

@rasmi rasmi Mar 27, 2026

Choose a reason for hiding this comment

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

Added server-side stage validation for cross-parameter checks!

progress: StageProgressConfig
timeLimitInMinutes: float | None = None
requireFullTime: bool | None = None
timeMinimumInMinutes: float | None = None
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Do we have any API client tests that we can use to exercise this?

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.

What do you mean? GH Actions fails if the typebox schemas and Python types are ever out of sync (the Python file is generated from the Typebox schemas using npm run update-schemas).

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.

Also -- API requests are validated through Typebox schema (and added stage validation at your suggestion!)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What I mean is, do we have any tests that send an API request using the parameter, and confirm that it does what we expect? I'm imagining a scenario where we accidentaly set up the API handling to ignore the parameter and just set it to default - everything would pass type validation but the feature wouldn't work. Would we catch that in tests?

(If the answer is "no, and a proper test framework for that would be too much work for this feature," that's fine, I don't want to hold this up until the infra is perfect or anything.)

discussions: config.discussions ?? [],
timeLimitInMinutes: config.timeLimitInMinutes ?? null,
requireFullTime: config.requireFullTime ?? false,
timeMinimumInMinutes: config.timeMinimumInMinutes ?? null,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This shouldn't need a separate null option; we can use 0 for no minimum, in the internal representation and probably the API. That way we don't have to wonder whether there's a difference between a 0 and a null.

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.

We allow a lot of options to remain unset across the codebase, I think it's nice to not have to specify certain optional things and have the codebase handle them appropriately. WDYT?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

From a UI perspective, definitely agree that we shouldn't have to specify optional things. From a backend perspective, my claim is that the appropriate way to handle it is to default the minimum to 0, instead of a separate null. Otherwise we have separate representations for "user didn't specify a minimum" and "user specified no minimum". That makes the code harder to reason about, and makes it possible for us to accidentally make them act differently.

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.

What if we make it so that it has to be non-zero if set? I think "user didn't specify a minimum" is a useful state to have, especially for optional features.

@rasmi rasmi force-pushed the min-time-clean branch 2 times, most recently from edb1b82 to 382cfbe Compare March 27, 2026 17:29
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.

2 participants