Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: auto-answer one at a time, not into the future #3764

Merged
merged 34 commits into from
Oct 29, 2024

Conversation

jessicamcinchak
Copy link
Member

@jessicamcinchak jessicamcinchak commented Oct 4, 2024

High-level goals / summary of changes:

  • upcomingCardIds is responsible for graph navigation based on answers so far only and does not check future node's data values for automation potential or queue up nodes based on optimistic automations
  • Question, Checklist, and Filter components are automated when they are reached, not any earlier. Each should leave an auto: true breadcrumb (Filters & Questions without edges don't leave any breadcrumbs currently)
    • Ideally by each component type becoming responsible for its own "visibility" (automated/hidden or empty/pre-populated & put to user), it'll become simpler to customise or extend automation logic to other component types in the future

Detailed changes:

  • Strip down upcomingCardIds
  • Add two new store methods autoAnswerableOptions & autoAnswerableFlag which takes current nodeId & outputs a list of ids that can be automated (ids are subset of current node's edges aka "options" aka "answers" aka "responses")
    • Passport value matching & startsWith granularity for Questions & Checklists
    • Flag matching for Filters
    • Matches many for Checklists, but limits to match left-most one for Questions & Filters
    • Blanks
    • _nots
  • Questions
    • Public wrapper to manage visibility
    • Editor toggle to force selection / forgo automation
  • Checklists
    • Public wrapper to manage visibility
    • Editor toggle to force selection / forgo automation
  • Filters
  • Review and update tests

Testing:
There's lot of old classic automation demo flows like:

Will also be asking content team to review full services; we need a plan of how to migrate "content work-arounds".

Pay special attention to:

  • When nodes are automated (eg not future)
  • How nodes are automated (eg passport should be retaining most granular value possible but automate less granular matching options; if passport values are set via Checklist then automated Question only selects left-most one, etc)
  • Blanks and "No result" flags
  • Planning constraints _nots (TODO!)
  • Ability to still navigate backwards as expected (eg skipping automated questions)
  • Automated answers and their corresponding flag value correctly populate Result "reasons"

Next steps / followup PRs:

  • Review usage of preview store methods that call upcomingCardIds - eg previousCard, setCurrentCard & isFinalCard
  • Replace or refactor collectedFlags & getResultData preview store methods
    • Goal to be able to compute flags on the fly from breadcrumbs and display in editor console like passport as navigating
  • Should GIS API return most granular values rather than least? (eg article4, flood)
  • Fix SetValue "remove" issue where passport value is removed but associated flag isn't, that can still lead to incorrect Filter automations here (same as on production)
  • Fix clones ordering issue which can still lead to seeing nodes in incorrect/unexpected order on branches here (same as on production)

@jessicamcinchak jessicamcinchak changed the title feat: feat: auto-answer one at a time, not into the future Oct 4, 2024
@jessicamcinchak jessicamcinchak added the demo Demo environment being used by an external team label Oct 4, 2024
@jessicamcinchak
Copy link
Member Author

Copy link

github-actions bot commented Oct 4, 2024

Removed vultr server and associated DNS entries

@jessicamcinchak
Copy link
Member Author

@jessicamcinchak
Copy link
Member Author

@jessicamcinchak jessicamcinchak removed the demo Demo environment being used by an external team label Oct 14, 2024
@jessicamcinchak jessicamcinchak marked this pull request as ready for review October 28, 2024 14:10
@jessicamcinchak jessicamcinchak requested a review from a team October 28, 2024 14:16
Copy link
Contributor

@DafyddLlyr DafyddLlyr left a comment

Choose a reason for hiding this comment

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

Great stuff here! 👏

Again, I really appreciate how much work this PR covers. Tests are clear and comprehensive which is going to be a huge help going forward. Likewise, the level of comments on the code is thorough and helpful.

Comments basically fall into three categories -

  • Taking the explicitness a step further by using named callback functions or using alternative variables names in a few places
  • Simplifying some nested conditional logic
  • Questions around where we should be running this check, especially in the context of automating on inputs - discussed earlier on the dev call

The nested conditions in autoAnswerableOptions() is the bit I had the hardest time reading and understanding here.

editor.planx.uk/src/@planx/components/Checklist/Editor.tsx Outdated Show resolved Hide resolved
editor.planx.uk/src/@planx/components/Checklist/Public.tsx Outdated Show resolved Hide resolved
editor.planx.uk/src/@planx/components/Checklist/Public.tsx Outdated Show resolved Hide resolved
editor.planx.uk/src/@planx/components/Checklist/model.ts Outdated Show resolved Hide resolved
Comment on lines +460 to +465
.sort(
(a, b) =>
// Sort by the most to least number of dot-separated items in data.val (most granular to least)
String(b.data?.val).split(".").length -
String(a.data?.val).split(".").length,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
.sort(
(a, b) =>
// Sort by the most to least number of dot-separated items in data.val (most granular to least)
String(b.data?.val).split(".").length -
String(a.data?.val).split(".").length,
)
.sort(byGranularity)

Another small idea for a named callback function that could help!


// If we have existing passport value(s) for this fn in an eligible automation format (eg not numbers or plain strings),
// then proceed through the matching option(s) or the blank option independent if other vals have been seen before
if (Array.isArray(passportValues) && passportValues.length > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

There's a lot of nested conditionality here which is hard to follow, it might be best to reverse conditions into guard clauses below a few times.

Suggested change
if (Array.isArray(passportValues) && passportValues.length > 0) {
if (!Array.isArray(passportValues) || !passportValues.length) {

Copy link
Member Author

Choose a reason for hiding this comment

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

I honestly just don't have the brain capacity to re-organise this one again right now, but promise to keep this in mind and try to revisit as I draft a Notion page with a human-readable explanation of our auto-answering rules !

Copy link
Contributor

Choose a reason for hiding this comment

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

Very fair! 😅

editor.planx.uk/src/pages/FlowEditor/lib/store/preview.ts Outdated Show resolved Hide resolved
Comment on lines +527 to +529
if (type === TYPES.Question) {
optionsThatCanBeAutoAnswered = optionsThatCanBeAutoAnswered.slice(0, 1);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The balance between "what's a component's responsibility" and "what's a store / navigation / graph traversal responsibility" is a tricky one!

This feels like it could comfortably fall into the useEffect() of the component itself, but doesn't seem wrong here either.

Just an observation really - very much happy to keep it here for now. If we find that this list of per-component exceptions grows, that might be a sign it's best handled elsewhere. I suspect what we'll end up with though is a continuation of the pattern you have here - functions responsible for how a single component, or a group of related components, handle auto answering.

Copy link
Member Author

@jessicamcinchak jessicamcinchak Oct 29, 2024

Choose a reason for hiding this comment

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

My argument for here rather than within useEffect of the component itself is that it's nice to be able to clearly test length of returned array throughout these logic unit tests ! Eg test cases where I know that there are many matching paths, but I want to confirm that I'm only going to auto-answer the most-granular, left-most option if my node is a Question

editor.planx.uk/src/pages/FlowEditor/lib/store/preview.ts Outdated Show resolved Hide resolved
@jessicamcinchak jessicamcinchak merged commit 02cbaf0 into main Oct 29, 2024
11 of 12 checks passed
@jessicamcinchak jessicamcinchak deleted the jess/automate-next-not-future branch October 29, 2024 15:00
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