1
0
Fork 0
mirror of https://github.com/IRS-Public/direct-file.git synced 2025-06-28 04:25:52 +00:00
direct-file/docs/adr/adr-optional-facts.md
2025-06-05 15:58:51 -04:00

249 lines
8 KiB
Markdown

---
# Configuration for the Jekyll template "Just the Docs"
parent: Decisions
nav_order: 100
title: "Optional facts"
# These are optional elements. Feel free to remove any of them.
status: "Decided"
date: "2023-11-14"
---
<!-- we need to disable MD025, because we use the different heading "ADR Template" in the homepage (see above) than it is foreseen in the template -->
<!-- markdownlint-disable-next-line MD025 -->
# Optional Facts
## Context and problem statement
The fact graph does not have a way to represent optional facts and we need to set certain fields such as W2 boxes and middle initials to be optional.
We need this feature for MVP.
## Desirable solution properties
We'd like the solution to this problem to
1. Allow us to show in the frontend to users that fields are optional.
2. Allow the user to leave the field blank and hit `Save and continue`.
3. Allow the fact graph to properly calculate downstream calculations without this fact.
## Considered options
1. Create a mechanism to allow specific writable facts to be left incomplete
1. Create the idea of null or default values in the fact graph/fact dictionary
## Decision Outcome
Chosen option: **Create a mechanism to allow specific writable facts to be left incomplete**
We do this by creating a second derived fact that is always complete. The original fact is prefixed with `writable-`. The derived fact uses the incompleteness of the writable fact to provide a default value. See below for instructions.
Reasoning: This one doesn't complicate our fact system with the ideas of placeholders, default values, `hasValue`s, validity etc because it keeps writable values separate from the downstream value. So it might be easier to do and easier to understand.
However, we felt in a v2 future version, we might do the other option. For now, we have proceeded with this option.
### Consequences
1. Good: We can start marking fields as optional.
2. Good: We can test that optional fields aren't breaking the flow downstream.
3. Good: We can test that visual treatment for optional fields works for users.
4. Bad: The scala option where we add the concept of optional fields into the graph itself might be more comprehensive.
### How to make a fact optional
Engineers looking to make a fact optional can do the following.
1. Find the component in `flow.tsx`. Not all fact types are enabled for optionality!!
Only `GenericString` fields and `TextFormControl` based fields (Dollar, Ein, Pin etc.) are enabled for optionality.
```xml
<Dollar path='/formW2s/*/wages'/>
```
* Add `required='false'` and rename to `writableWages`.
We must rename the fact, because we have to ensure no derived facts get marked as optional.
```xml
<Dollar path='/formW2s/*/writableWages' required='false' />
```
2. Find out if there should be a default value for this fact, or if it can be left incomplete.
* Dollar values can often use 0 as a default.
* Strings or enums may not have a correct default, and we may want to leave these incomplete.
* An incomplete fact can break other parts of the flow so we should verify with backend before leaving it incomplete.
* Reach out on Slack to get guidance from backend team members.
**IF DEFAULT IS NEEDED:** Find the fact in `ty2022.xml` or other fact dictionary files, and create a derived version that is always complete.
It uses the incompleteness of the writable fact to provide a default value.
* Replace this:
```xml
<Fact path="/formW2s/*/wages">
<Name>Wages</Name>
<Description>
Box 1 of Form W-2, wages, tips, and other compensation.
</Description>
<Writable>
<Dollar />
</Writable>
<Placeholder>
<Dollar>0</Dollar>
</Placeholder>
</Fact>
* With this (be sure to remove `<Placeholder>` if there is one):
```xml
<Fact path="/formW2s/*/writableWages">
<Name>Wages</Name>
<Description>
Box 1 of Form W-2, wages, tips, and other compensation.
This is the writable optional fact. Can be left incomplete.
Please use the derived fact in downstream calculations.
</Description>
<Writable>
<Dollar />
</Writable>
</Fact>
<Fact path="/formW2s/*/wages">
<Name>Wages</Name>
<Description>
Box 1 of Form W-2, wages, tips, and other compensation.
</Description>
<Derived>
<Switch>
<Case>
<When>
<IsComplete>
<Dependency path="../writableWages" />
</IsComplete>
</When>
<Then>
<Dependency path="../writableWages" />
</Then>
</Case>
<Case>
<When>
<True />
</When>
<Then>
<Dollar>0</Dollar>
</Then>
</Case>
</Switch>
</Derived>
</Fact>
```
**IF DEFAULT IS NOT NEEDED:** Find the fact in `ty2022.xml` or other fact dictionary files, and create a derived version that may be incomplete.
* Replace this (don't remove the Placeholder):
```xml
<Fact path="/formW2s/*/wages">
<Name>Wages</Name>
<Description>
Box 1 of Form W-2, wages, tips, and other compensation.
</Description>
<Writable>
<Dollar />
</Writable>
<Placeholder>
<Dollar>0</Dollar>
</Placeholder>
</Fact>
```
with this:
```xml
<Fact path="/formW2s/*/writableWages">
<Name>Wages</Name>
<Description>
Box 1 of Form W-2, wages, tips, and other compensation.
</Description>
<Writable>
<Dollar />
</Writable>
<Placeholder>
<Dollar>0</Dollar>
</Placeholder>
</Fact>
</Fact>
<Fact path="/formW2s/*/wages">
<Name>Wages</Name>
<Description>
Box 1 of Form W-2, wages, tips, and other compensation.
</Description>
<Derived>
<Dependence path='../writableWages' />
</Derived>
</Fact>
```
3. Search the `flow.tsx` for other components using the writable fact and update the fact name.
4. Rebuild the fact dictionary code
* In `direct-file/df-client/fact-dictionary` run
```sh
npm run build
```
5. Edit `en.yaml` and the other locales to replace field labels for the writable fields
```yaml
/formW2s/*/writableWages:
name: Wages, tips, other compensation
```
6. Finally, run tests and fix any testcases that should have the writable field, or alternately the derived field.
## Pros and Cons
### Create a mechanism to allow specific writable facts to be left incomplete
We do this by creating a second derived fact that is always complete. The original fact is prefixed with `writable-`. The derived fact uses the incompleteness of the writable fact to provide a default value.
#### Pros
* Lower lift
* Doesn't complicate the fact system with placeholders and potentially avoids complex bugs in the fact system at this late stage.
* Easier to understand.
#### Cons
* It's likely more correct and complete for our fact system to understand optionality.
### Create the idea of null or default values in the fact graph/fact dictionary
In this method, we would change the scala and the factgraph to handle the concept of null or default values.
If something has a default value in the fact dictionary, we pick that up on the frontend (similar to how we do enumOptions) and then let a person skip the question, using the default value in its place.
#### Pros
* This might be more logically correct as we're not overloading the concept of `incomplete` with `optional+empty`
#### Cons
* Bigger lift than the other option.
* Requires scala rework which we have less engineering bandwidth for.
* Currently, every writable fact is either `incomplete + no value`, `incomplete + placeholder`, or `complete`. Making this change would add a fourth state of `incomplete + default value` and that might have multiple downstream consequences in our application.