KQ-2057 · ASSUMPTION/PINS
Assumption Pins
An AI answer with the assumptions it rests on pinned beside it, every sentence linked to the pins it depends on: focusing a pin lights its sentences and draws a comb across the gutter to them on springs.glide. Editing a pin re-runs the answer, but only the sentences whose words change dissolve in place on the exit ease and stream back word by word while the rest hold still, each keeping an underline that sweeps in on glide; a paragraph whose line count changed glides to its new height, and two pins that contradict are bracketed together while Use this answer waits with the reason. Pins are a roving list — arrows move, Enter edits inline, Escape cancels or reverts — and under 40rem they become a strip of chips above the answer.
Fernworks Model 3
rests on 5 assumptions
Assumptions
What will the new platform team cost Fernworks this year?
Four engineers starting in April are on payroll for nine months of this year. Each costs €102k a year with employer costs, on an average salary of €82k plus 24%. That puts this year's payroll at €305k.
Recruiting fees add a one-off €49k, at 15% of first-year salary per hire. Together that's €354k, €46k inside the €400k cap. Equipment sits in its own budget, so laptops and licences aren't counted here.
Starting in April keeps the platform launch on track for the autumn. Two things to check before you commit: whether the cap includes recruiting fees, and whether any hire is a contractor, who carries no employer costs.
Arrow keys move between assumptions. Enter edits one; Escape cancels an edit, or reverts a changed assumption.
5 assumptions · 8 sentences · fernworks hiring budget
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/assumption-pins
Props
- pinStyle
- "tack" | "tag" | "rule"
- default "tack"
- Pins drawn as cards with a round pin head, notched tags, or bare rules.
- highlight
- "wash" | "line" | "focus"
- default "wash"
- How a pin's sentences light: a tinted wash, a thick underline, or full ink while every other sentence dims.
- accent
- string
- default "var(--accent-bright)"
- Any CSS colour for pin numbers, the lit wash, the rewrite underline, the comb and Use this answer.
- question
- string
- default the Fernworks budget question
- The question the answer replies to.
- assumptions
- Assumption[]
- default defaultAssumptions
- The pins, in order: id, label, the value the answer was written with, and options (a radiogroup) or number limits and a unit, plus where it came from.
- values / defaultValues
- AssumptionValues
- default — / each assumption's value
- The assumption values, controlled or initial.
- onValuesChange
- (values: AssumptionValues) => void
- default —
- Fires from the edit or revert that changed a value, with every value.
- compose
- (values: AssumptionValues) => AnswerParagraph[]
- default composeFernworksAnswer
- Writes the answer from the values; sentences keep stable ids and list the assumptions they depend on, so only those whose words change are rewritten.
- conflicts
- (values: AssumptionValues) => AssumptionConflict[]
- default fernworksConflicts
- Finds pairs of assumptions that cannot both hold, each with a one-sentence reason.
- onEditAssumption
- (id, value, previous) => void | Promise<unknown>
- default —
- An assumption was edited. Return a promise to hold the rewrite until the host has re-run the answer.
- onAcceptAnswer
- (text: string, values: AssumptionValues) => void
- default —
- Use this answer was pressed, with the answer as plain text.
- onRevert
- (id: string, value: AssumptionValue) => void
- default —
- An assumption went back to the value the answer was first written with (Escape on a changed pin, or its revert button).
- status
- "ready" | "loading" | "error"
- default "ready"
- Loading draws skeleton lines; error offers Try again.
- onReload
- () => void
- default —
- Try again was pressed after the answer failed to load.
- model
- string
- default "Fernworks Model 3"
- The model answering, named in the header.
- rerunDelay
- number
- default 650
- How long a rewrite holds its shimmer before streaming, in ms.
- streamSpeed
- number
- default 28
- Words a second as a rewritten sentence streams back in.
- underlineHold
- number
- default 2600
- How long a rewritten sentence keeps its underline, in ms.
- height
- number
- default 540
- The surface's height in px; the answer scrolls inside it.
- disabled
- boolean
- default false
- Nothing can be edited or accepted.
- className
- string
- default —
- Classes for the outer surface.
| Prop | Type | Default | Description |
|---|---|---|---|
| pinStyle | "tack" | "tag" | "rule" | "tack" | Pins drawn as cards with a round pin head, notched tags, or bare rules. |
| highlight | "wash" | "line" | "focus" | "wash" | How a pin's sentences light: a tinted wash, a thick underline, or full ink while every other sentence dims. |
| accent | string | "var(--accent-bright)" | Any CSS colour for pin numbers, the lit wash, the rewrite underline, the comb and Use this answer. |
| question | string | the Fernworks budget question | The question the answer replies to. |
| assumptions | Assumption[] | defaultAssumptions | The pins, in order: id, label, the value the answer was written with, and options (a radiogroup) or number limits and a unit, plus where it came from. |
| values / defaultValues | AssumptionValues | — / each assumption's value | The assumption values, controlled or initial. |
| onValuesChange | (values: AssumptionValues) => void | — | Fires from the edit or revert that changed a value, with every value. |
| compose | (values: AssumptionValues) => AnswerParagraph[] | composeFernworksAnswer | Writes the answer from the values; sentences keep stable ids and list the assumptions they depend on, so only those whose words change are rewritten. |
| conflicts | (values: AssumptionValues) => AssumptionConflict[] | fernworksConflicts | Finds pairs of assumptions that cannot both hold, each with a one-sentence reason. |
| onEditAssumption | (id, value, previous) => void | Promise<unknown> | — | An assumption was edited. Return a promise to hold the rewrite until the host has re-run the answer. |
| onAcceptAnswer | (text: string, values: AssumptionValues) => void | — | Use this answer was pressed, with the answer as plain text. |
| onRevert | (id: string, value: AssumptionValue) => void | — | An assumption went back to the value the answer was first written with (Escape on a changed pin, or its revert button). |
| status | "ready" | "loading" | "error" | "ready" | Loading draws skeleton lines; error offers Try again. |
| onReload | () => void | — | Try again was pressed after the answer failed to load. |
| model | string | "Fernworks Model 3" | The model answering, named in the header. |
| rerunDelay | number | 650 | How long a rewrite holds its shimmer before streaming, in ms. |
| streamSpeed | number | 28 | Words a second as a rewritten sentence streams back in. |
| underlineHold | number | 2600 | How long a rewritten sentence keeps its underline, in ms. |
| height | number | 540 | The surface's height in px; the answer scrolls inside it. |
| disabled | boolean | false | Nothing can be edited or accepted. |
| className | string | — | Classes for the outer surface. |