Skip to content

fix: IndiGo tab and picker (#62), native dropdowns, calendars, verify flakes, streamed replies - #74

Merged
senamakel merged 6 commits into
tinyhumansai:mainfrom
YellowSnnowmann:fix/62-book-tab-and-picker
Oct 5, 2026
Merged

senamakel merged 6 commits into
tinyhumansai:mainfrom
YellowSnnowmann:fix/62-book-tab-and-picker

Conversation

@YellowSnnowmann

@YellowSnnowmann YellowSnnowmann commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Five fixes that stopped browser tasks partway through, or made them slow. Each fix is in its own commit(s).

1. IndiGo's "Book" tab and city-picker search (#62)

These are the two original commits of this PR, unchanged.

  • A "Book" tab refused as irreversible. A tab only shows another panel of the page. A stop_before phrase therefore no longer names one, and on a payment page choosing a tab ("UPI", "Cards") counts as filling the form, like picking a saved-card radio. A tab's own label is still checked against the denylist. The tab role is only what the page claims, so a tab labelled "Pay ₹7,346" stays gated.
    • Separately, a stop_before phrase now names a control only where the control's label starts a word in the phrase. "Send" still matches "sending the email"; "Rent" no longer matches "the current bill".
    • The word-start rule alone can't fix "Book", because "booking" starts with it. That is why the tab rule is needed.
  • City-picker search refused with INVALID_TARGET. IndiGo's picker opens without focusing its search input, so text typed at the focus is refused. choose used to record that as typed, tell Jev so, and spend the attempt. It now grounds the widget's search box in the same attempt and records nothing as typed.

2. Native dropdowns and datalist suggestions can be chosen (fc9d174a)

A native <select> and a text box's suggestions (<input list> with a <datalist>) show their choices in a menu Chrome draws outside the page. A click opens that menu where nothing reads or presses it, and the page looks unchanged.

So BlazeDemo's departure city and Selenium's "Dropdown (select)" and "Dropdown (datalist)" could never be chosen. On the datalist, choose looped for 77 Jev calls, then failed.

  • Sight offers each enabled choice as an option inside its control:

    • at most 60 per control, under a listbox "<control>" container;
    • selected when chosen;
    • a suggestion is named by the value it fills in, with a differing label as its description;
    • suggestions two boxes share are offered only under the focused box. Each suggestion is marked (data-tc-for) with the box it was offered under.
  • Pressing such an option (native_select.rs) chooses it the way a person does, without opening the menu:

    • it selects the dropdown's option, or sets the box's value through the input's own value setter, so React sees the change;
    • it fires input and change;
    • it succeeds only once the choice holds.

    Any other option, such as a page's own role="option" row, is clicked as before.

  • Labels: a label that wraps its dropdown, and a text block that holds one, are read without the dropdown's own text. Selenium's dropdown used to be named "Dropdown (select) Open this select menu One Two Three".

3. Planner, rescuer and shaper replies are streamed (f0f6f053)

Tiny Humans' gateway answers HTTP 504 to a request that sends nothing back for 60 seconds. Unstreamed, nothing comes back until a reasoning model has written its whole reply.

On agentic-v1, a small rescue prompt took 25 to 45 s, and a real one took longer: one task's rescue started at 12:57:44 and failed with a 504 at 12:58:44. Every hosted call is now streamed and gathered into one reply. A route that ignores streaming still answers in one piece.

4. A date picker's days and arrows can be pressed (11825daf)

Bootstrap's date picker, among others, draws each day as a plain <td> that shows a pointer only under the mouse. So sight never offered the days as controls.

On Selenium's web form, a "set the date" step opened the calendar and found no day to press. Two rescues spent 133 Jev calls pressing nothing, and a third typed the date instead: 269 s in all. The paging arrows read as "»" and "«", and choose only pages a calendar through a control named "next month".

  • The calendar: a shown table with at least 28 day-number cells counts as a calendar when its month and year ("November 2026") are named in its own heading, or in a short header just before it. A table of numbers whose month is named only elsewhere on the page is not a calendar.
  • Its days: each enabled day becomes a gridcell named by its number and described by the date it stands for ("15 November 2026"). Days before the month's first and after its last are dated in the months either side. A week-number column is left out.
  • Its arrows: inside a calendar's container, an arrow glyph or a bare "Next" reads as "next month", and its opposite as "previous month".

5. A crisp coverage carries a hedged condition (abbe17e2)

verify, wait_for, if and repeat_until ask a condition three ways: yes/no, its negation, and a five-level coverage. The coverage is there because a condition that lists several things draws a hedged yes/no but a crisp coverage answer. The two were averaged, though, and the average cannot clear the 0.75 bar unless the coverage is certain.

On BlazeDemo, "the purchase form shows the passenger name, street address, city, state, and zip code" was judged 0.71 with every field filled (yes/no 0.52, coverage 0.88). The step failed, and a rescue only confirmed the form was done.

  • The rule: a condition's calibrated yes/no within HEDGED (0.10) of an even chance now defers to a coverage whose top level is at least CRISP_TOP (0.85). This is ask::deferred.
  • The screen-only view: the deep level's screen-only view now asks the coverage too, and is read the same way.
  • Unchanged: a yes/no that leans either way is averaged as before, so a clear "no" is never overruled by the coverage. A do step's completion keeps its plain average with progress.

Related issue

Closes #62. Part of tinyhumansai/openhuman#7000. The host side is tinyhumansai/openhuman#7008, and vendor/tinycomputer is re-pinned there once this ships.

API or behavior changes

No API or wire changes. Behavior changes:

  1. is_destructive: role tab is exempt from stop_before naming and from the payment-page blanket gate. It is not exempt from the label denylist.
  2. named_in_stop_before matches only at the start of a word.
  3. choose: a refused focus type falls through to type_to_filter in the same attempt, and is no longer reported to Jev as typed.
  4. Sight lists native dropdown choices and datalist suggestions as option nodes inside their control. Labels and text blocks no longer carry a dropdown's option text.
  5. Clicking a native option sets its control's value instead of clicking. A disabled, read-only or vanished option or control fails with ACTION_FAILED.
  6. Hosted planner, rescue and output calls are streamed.
  7. Sight offers a calendar's days as gridcells described by their dates, and names its arrows "next month" and "previous month".
  8. A condition check takes a crisp coverage over a hedged yes/no. There are two new thresholds, HEDGED 0.10 and CRISP_TOP 0.85, listed in docs/technical/decision-thresholds.md.

Validation

Commands actually run on macOS (arm64). The checkout for items 2–7 was this head merged with #75: git merge-tree gives that checkout's exact tree.

  1. cargo fmt --all -- --check: pass.
  2. cargo clippy --release -p tinycomputer-browser -p tinycomputer-engine --all-targets --all-features -- -D warnings: pass. The IndiGo booking widget: city picker search is INVALID_TARGET, and a "Book" tab is classified irreversible (Kashmir flow no longer passes) #62 commits were also checked with --workspace --exclude tinycomputer-accessibility. That crate's macOS-only code has clippy failures locally that predate this change and that Linux CI never compiles. Its paste test also types into whichever app has focus on macOS.
  3. cargo test --release --all-features -p tinycomputer-browser: 109 passed, and 2 doctests passed.
  4. cargo test --release --all-features -p tinycomputer-engine: 356 passed. With -p tinycomputer: 44 passed. That makes 400 in all.
  5. Live sight tests, TINYCOMPUTER_LIVE_BROWSER=1 on Chrome for Testing 148: 6 passed, including the two new ones.
  6. scripts/build-module (release): built and attested.
  7. Live runs: task_live drove the attested module over TinyBus on Tiny Humans' routes, with agentic-v1 (task_live's default) for the planner, rescue and output.
Task Before fixes 4 and 5 (headed) After (headless)
Selenium web form: text, dropdown, datalist, checkbox, radio, date, then ask before Submit stopped for approval at Submit after 269 s: "set the date" found no day to press; three rescues, then typed it stopped for approval at Submit in 57 s, no rescue, verify 0.80
BlazeDemo: cheapest Boston → London flight, passenger details, stop before payment reached the payment checkpoint in 99 s after a rescue: verify failed at 0.71 on a filled form reached the payment checkpoint in 84 s, no rescue, verify 0.90
Selenium, date by calendar: "pick 15 November 2026 by clicking that day in its calendar" — pressed "next month", then choose pressed day "15" in 7 Jev calls; the field holds 11/15/2026. 65 s

In the BlazeDemo run after the fix, the full view's yes/no hedged twice (0.48 and 0.53) against a coverage of 0.86 and 0.91. The old average (0.67 to 0.72) would have failed the step again.

Earlier runs of the same two tasks with fixes 1–3, by model for all three roles:

Task agentic-v1 openrouter/deepseek/deepseek-v4-flash chat-v1
Selenium web form 59 s 37 s 33 s
BlazeDemo 106 s (before streaming); a streamed run failed in 186 s when its rescue ran past the 120 s limit 43 s 40 s

task_live exits 1 when a task stops for approval, because it only counts a finished task or the payment checkpoint as a pass. Stopping before Submit is what those tasks asked for.

Not yet re-run live against goindigo.in. Replaying tasks/kashmir/plan.json is the next check for #62.

Tests

  • view_tests::a_stop_before_phrase_names_a_control_only_from_the_start_of_a_word

  • view_tests::a_tab_is_navigation_unless_its_own_label_reads_irreversible:

    • a "Book" tab passes under "paying for the booking", while a "Book" button stays gated;
    • "Pay ₹7,346" and "Pay now" tabs stay gated, with and without card fields on screen;
    • a "UPI" tab on a payment page passes;
    • an unnamed tab in a sheet stays gated.
  • choose_tests::choose_finds_the_search_box_when_the_opened_widget_leaves_no_focus uses a new simulator quirk, NoFocus, which gives the browser's INVALID_TARGET refusal. The test asserts that the city lands in the search box and that Jev is never told the refused text was typed.

  • native_select_tests:

    • a native option is chosen by value with no click;
    • a refused one fails without a click;
    • a page's own role="option" row, and a tree ref, are clicked as before.
  • live_tests::live_native_choices_are_offered_as_options_and_chosen_by_value runs in a real browser and checks:

    • choice names and containers;
    • a disabled choice is left out;
    • a label wrapping its dropdown reads without the choices;
    • shared suggestions wait for focus;
    • choosing fires change;
    • selected shows after choosing.
  • live_tests::live_a_date_pickers_days_are_offered_with_the_dates_they_stand_for uses a Bootstrap-style calendar (hover-only pointer, «/», days from the months either side, a disabled day), a jQuery-UI-style one (month named in a header before the table, a "Next" link) and a "Season scores" table of 1–28. It checks:

    • 72 days, each with its date;
    • the disabled day is left out;
    • none of the scores counts as a day;
    • the three month arrows.
  • deliberation_tests::a_hedged_yes_no_defers_to_a_crisp_coverage:

    • yes/no 0.52 with coverage 0.88 passes;
    • with coverage 0.6 it fails;
    • a yes/no of 0.2 with coverage 0.95 fails.

    It fails without the fix: with the plain average restored, the first case ends StepFailed. a_condition_split_across_views_does_not_pass now also asserts that the screen-only view asks the coverage. The simulator's oracle lets a test script a coverage directly (top_at).

  • Deliberately not unit-tested: the streaming switch in planner/hosted.rs. The hosted route accepts only the provider's own endpoints, so a local server cannot stand in. The client's stream handling is tested in tinyinference. Every live run after that commit planned over the stream, and an agentic-v1 rescue ran its full 120 s with no 504.

Documentation

  • docs/safety-and-privacy.md
  • docs/technical/architecture.md
  • docs/technical/decision-loops.md
  • docs/technical/decision-thresholds.md
  • docs/technical/specs/browser-sight.md
  • docs/technical/specs/jev-deliberation.md
  • docs/crates/tinycomputer-engine/flow/the-do-loop.md
  • docs/crates/tinycomputer-engine/flow/step-kinds.md
  • docs/crates/tinycomputer-engine/planner.md

docs/technical/decision-loops.md was already 507 lines, over the 500-line limit, before this PR. This PR adds 2 lines to it.

Checklist

  • Each fix is its own commit: six commits, five fixes, collected in one PR on request. Fixes 2 and 3 were each checked to apply alone to main.
  • No new #[allow(...)], #[ignore], or relaxed lints
  • No secrets, tokens, or .env contents in the diff or the description

Notes for review:

  • Tab rule: it changes safety policy. I deliberately kept tabs under the denylist, because a page can mark anything role="tab". If you would rather drop the payment-page exemption for tabs, that is a one-line change.
  • Deferral rule: it changes a decision threshold. It is scoped to conditions; a do step's completion is untouched. HEDGED and CRISP_TOP are documented with the other thresholds.
  • data-tc-for mark: a suggestion carries this mark beside data-tc-seen. A suggestion pressed from an older reading fills whichever box it was last offered under.

A tab only shows another panel of the page, so a stop_before phrase no
longer names one and, on a payment page, choosing one is filling the form
like a saved-card radio. IndiGo keeps its flight search behind a tab
labelled "Book", which a flow stopping before "paying for the booking"
named and refused, so no step could open the search form (tinyhumansai#62). A tab's
own label still counts against the denylist: the role is only the page's
claim, so a tab labelled "Pay ₹7,346" stays gated.

A stop_before phrase now names a control only where its label starts a word
of the phrase: "Send" is still named by "sending the email", "Rent" is no
longer named by "the current bill".
A widget that opens without focusing a field refuses text typed with no
target (INVALID_TARGET on the browser). choose recorded that as typed, told
Jev so, and spent the attempt; it now grounds the widget's search box in the
same attempt and records nothing as typed (IndiGo's city pickers, tinyhumansai#62).
@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5f5700ef-3054-4148-8622-631605bc0384
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@tinysweeper

tinysweeper Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

⚠️ Review failed for abbe17e21d10. the review of #74 did not finish within 900s

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Requesting changes: 1 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0161 · 279,250 in / 20,934 out · 27,658 cached (10%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0087 · 131,064 in / 11,761 out · 14,586 cached (11%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0058 · 111,268 in / 4,159 out  · 13,072 cached (12%) · gpt-5.6-luna
tests:       $0.0000 · 18,979 in  / 1,507 out  · 0 cached (0%)       · glm-5.3-flash
description: $0.0001 · 9,392 in   / 120 out    · 0 cached (0%)       · glm-5.3-flash

// city pickers, tinycomputer#62).
1 if into_focus => {
if !self.type_into_focus(log, option).await? {
self.type_to_filter(log, screen, what, option).await?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique confident

Only record filtering after the fallback succeeds

When the focused TypeText operation returns ok == false, this fallback calls type_to_filter. That function unconditionally inserts the target into typed and sets log.filtered = true before checking reply.ok, so a target that also rejects the text is recorded as successfully filtered even though no text was entered. This new call makes that failure path reachable for focused widgets and can cause later logic to skip required filtering or report a false success. Update type_to_filter to record typed and filtered only when its operation succeeds.

[RULE] incorrect-state-update ·

|| named_in_stop_before(name, stop_before)
|| (!navigation && named_in_stop_before(name, stop_before))
|| (screen.surface == "sheet" && candidate.name.is_none())
|| (!is_form_control(candidate)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority high security confident

Keep payment controls gated regardless of the tab role

On a payment screen, any candidate reported with role tab now bypasses the generic payment safety gate, even when its label is non-destructive (for example, Continue). Accessibility roles come from the current page and are not a trustworthy authorization signal; a page can mislabel a submission or payment action as a tab, allowing the flow to press it before the payment confirmation step. Do not exempt navigation roles from the payment evidence gate unless the candidate is independently verified as non-activating navigation.

[RULE] authorization-bypass ·

A native dropdown (<select>) and a text box's suggestions (<input list>
with a <datalist>) draw their choices in a menu outside the page. A click
on the control opens that menu where nothing reads or presses it, so
BlazeDemo's departure city and Selenium's "Dropdown (select)" and
"Dropdown (datalist)" could never be chosen: the choose step looped until
its budget ran out (77 Jev calls for the datalist).

Sight now offers each enabled choice, up to 60 per control, as an option
inside its control, `selected` when chosen. Suggestions two boxes share
are offered under the focused one only, and each suggestion is marked
with the box it was offered under. Pressing such an option sets the
control's value the way a person's choice does (a suggestion through the
input's own value setter, so React sees it), fires input and change, and
succeeds only once the choice holds. Any other option is pressed as
before.

A label wrapping its dropdown, and a text block holding one, are read
without the dropdown's text: Selenium's dropdown was named "Dropdown
(select) Open this select menu One Two Three".
Tiny Humans' gateway answers HTTP 504 to a request that sends nothing back
for 60 seconds. Unstreamed, nothing comes back until a reasoning model has
written its whole reply, which for a rescue on agentic-v1 took 25 to 45
seconds on a small prompt and longer on a real one: a task that needed a
rescue gave up on a gateway timeout instead (the rescue began at 12:57:44
and failed at 12:58:44).

Every hosted call is now streamed and gathered into one reply, so the
gateway sees the answer arriving from its first second. A route that
ignores streaming still answers in one piece: the client reads a plain
JSON body as the whole reply.
@YellowSnnowmann YellowSnnowmann changed the title fix(flow): let IndiGo's Book tab and city-picker search through (#62) fix: IndiGo Book tab and picker (#62), native dropdowns, streamed model replies Oct 5, 2026

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Requesting changes: 1 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0302 · 503,188 in / 40,568 out · 39,196 cached (8%)  · gpt-5.6-luna, glm-5.3-flash, deepseek-v4.1-flash
critique:    $0.0205 · 282,419 in / 24,829 out · 20,116 cached (7%)  · gpt-5.6-luna, glm-5.3-flash
security:    $0.0090 · 146,956 in / 11,327 out · 17,992 cached (12%) · gpt-5.6-luna
tests:       $0.0004 · 37,365 in  / 1,048 out  · 1,088 cached (3%)   · glm-5.3-flash
description: $0.0002 · 18,113 in  / 502 out    · 0 cached (0%)       · glm-5.3-flash

// inside its control, drawn in the control's box, and pressing one sets
// the control's value (`native_select.rs`).
const choicesOf = (element) => {
if (tag(element) === 'select') return element.multiple ? [] : [...element.options];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique confident

Offer options for multiple selects

A reachable <select multiple> is represented as a combobox but receives no option nodes at all, so the reader cannot select any of its enabled choices through the newly added option path. The surrounding documentation promises choices for native dropdowns without excluding multiple selects. Return the options for multiple selects as well, or explicitly represent their supported selection semantics instead of silently dropping them.

Suggested change
if (tag(element) === 'select') return element.multiple ? [] : [...element.options];
if (tag(element) === 'select') return [...element.options];

[RULE] incomplete-control-support ·

pub(super) const CHOOSE_JS: &str = r#"(option => {
if (!option || option.tagName !== 'OPTION') return null;
const group = option.parentElement;
if (option.disabled || (group && group.tagName === 'OPTGROUP' && group.disabled)) return false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique confident

Honor disabled fieldset inheritance

This only checks the option's own disabled state and an explicitly disabled optgroup. A select or datalist owner inside <fieldset disabled> can still have select.disabled/owner.disabled false, so this path changes the control and dispatches input/change even though the native control is disabled to the user. Check the effective disabled state (for example with the :disabled pseudo-class or an equivalent fieldset-ancestor check) for both the option and its owning control before applying the value.

[RULE] incomplete-disabled-state-check ·

Comment on lines +656 to +657
const list = tag(element) === 'input' ? element.list : null;
if (!list || element.readOnly) return [];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique confident

Restrict datalist choices to text-capable inputs

HTMLInputElement.list can be present on input types that do not show datalist suggestions, such as checkbox and radio inputs. For example, <input type="checkbox" list="choices"> reaches this branch and emits option nodes even though the browser does not offer that list under the control; pressing one can then incorrectly attempt to fill a non-text control. Gate this path on the same text-capable input predicate used by the rest of the reader.

Suggested change
const list = tag(element) === 'input' ? element.list : null;
if (!list || element.readOnly) return [];
const list = tag(element) === 'input' ? element.list : null;
if (!list || element.readOnly || !takesText(element)) return [];

[RULE] invalid-control-assumption ·

self.show_cursor(reference);
}
// A native option is chosen by value: a click opens an unseen menu.
if let Some(reply) = self.choose_if_native(operation, target.as_ref()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority high security uncertain

Keep payment controls gated regardless of the tab role

This new early return handles option clicks before the normal operation match, so any payment-control authorization performed in that path is skipped for native options. Apply the same payment-control gate before dispatching the native-option action, or have choose_if_native refuse gated targets.

[RULE] authorization-bypass ·

if (!list || element.readOnly) return [];
// Suggestions two boxes share are offered under the one being typed
// in, so that pressing one names a single box to fill.
const users = [...document.querySelectorAll('input[list]')].filter((other) => other.list === list);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium tests likely

Shared-suggestion focus gate has no non-live test

The new users.length > 1 && document.activeElement !== element gate decides whether suggestions shared by two boxes are offered at all. It is only exercised inside live_native_choices_are_offered_as_options_and_chosen_by_value, which is behind #[cfg(feature = "agent-browser")] and a TINYCOMPUTER_LIVE_BROWSER=1 environment check, so on a machine without a display server it silently drops out — which the repository rules explicitly require tests to survive. The visible decision here is pure DOM logic that a fixture could pin without a browser; without one, a refactor that breaks the gate (say, dropping the activeElement check) leaves every offline test green.

[RULE] missing-test-branch ·

Bootstrap's date picker, among others, draws each day as a plain table
cell that shows a pointer only under the mouse, so sight never offered
the days as controls. On Selenium's web form a "set the date" step opened
the calendar, found no day to press, and three rescues later typed the
date instead (269 s). Its paging arrows read as "»" and "«", which
`choose` does not take for "next month".

A shown table with at least 28 day-number cells, whose month and year its
own heading or a short header just before it names, is now a calendar:
each enabled day is a gridcell named by its number and described by the
date it stands for ("15 November 2026"), the days around the month dated
in the months either side, and a week-number column left out. Inside a
calendar's container an arrow glyph or a bare "Next" reads as "next
month", and its opposite as "previous month", which is how `choose` pages
a calendar to a date. A table of numbers whose month is named only
elsewhere on the page is not a calendar.
A condition that lists several things draws a hedged yes/no but a crisp
coverage answer; that is what the coverage question is for. Averaged, the
two cannot clear the 0.75 bar unless the coverage is certain. On
BlazeDemo, "the purchase form shows the passenger name, street address,
city, state, and zip code", with every field filled, was judged 0.71
(yes/no 0.52, coverage 0.88): the step failed and a rescue only confirmed
the form was done.

A condition's calibrated yes/no within 0.10 of an even chance now defers
to a coverage whose top level is at least 0.85 (`ask::deferred`), also in
the deep level's screen-only view, which now asks the coverage too. A
yes/no that leans either way is averaged as before, so a clear "no" is
never overruled by the coverage, and a do step's completion keeps its
plain average with progress.
@YellowSnnowmann YellowSnnowmann changed the title fix: IndiGo Book tab and picker (#62), native dropdowns, streamed model replies fix: IndiGo tab and picker (#62), native dropdowns, calendars, verify flakes, streamed replies Oct 5, 2026
@senamakel
senamakel merged commit 123826a into tinyhumansai:main Oct 5, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IndiGo booking widget: city picker search is INVALID_TARGET, and a "Book" tab is classified irreversible (Kashmir flow no longer passes)

2 participants