Architecture decision records
Why Modyra is built the way it is. Each record states the pressure that forced a decision, what was decided, what it costs, the alternatives that lost and why, and the check that fails if the decision is violated.
Every architectural or security decision belongs here. A decision recorded only in a commit message, a changeset, or a file version control ignores is a decision the next reader will relitigate from scratch — an untracked file is not a durable record at all.
Use TEMPLATE.md. A record is not complete without Verification and Security and privacy; where either is genuinely empty, say so explicitly rather than omitting the section — an absent section reads as an oversight, and “no security impact” is a finding.
The records
Section titled “The records”| 0001 | Project and contract model | What a Studio project is, and how it relates to the contract it compiles to |
| 0002 | Ids and paths | Stable node ids for editing, dotted paths for reading — and where each belongs |
| 0003 | Command engine | Every edit is a command, which is what makes undo, redo and grouping possible |
| 0004 | Target plugin API | How a code-generation target is added without changing the model |
| 0005 | Expressions and references | The portable operator set, and why a reference is an id rather than an accessor |
| 0006 | One UI contract, many consumers | @modyra/widgets is the UI contract; renderers consume it and never redefine it |
| 0007 | Expressions are data, never code | No eval on a document that arrives over a network. The security decision of the dynamic contract |
| 0008 | The preview has no privileged path | What a designer watches is what a designer exports |
| 0009 | Client validation is defence in depth | The trust boundary, stated plainly: the server is the authority |
| 0010 | Every claim has an executable check | Ratchets, gates, and why a check nobody has watched fail is only a claim |
| 0011 | A capability names its event | A boolean answers whether and leaves how to each renderer, which is a specification by accident — superseded by 0013 |
| 0012 | A choice is a radio, by tag or by role | All three renderers already chose radiogroup; the open question was whether the tag is required |
| 0013 | The dismissal names its gesture | One event cannot express where a gesture began and ended, which is what the dismissal rule turns on |
| 0014 | The contract names the responsible element | Naming the region and not the element inside it let three widgets conform that nobody could operate |
| 0015 | Light text while it is readable | The contrast ratio and a reader disagree about saturated colour, and the ratio was winning |
| 0016 | A multiselect is one kind, and its mode is not the contract’s | Decided on a premise that was false — the mode was already contract data — superseded by 0017 |
| 0017 | A varianted kind names its anatomy per configuration | A disjunction says something is operable; ADR 0014 asks which element, and only a variant can answer |
| 0018 | A select declares whether it filters | One widget, three behaviours and one of them broken, because the distinction was not contract data |
| 0019 | TypeScript 7 compiles the libraries | Two consumers pin the compiler and the rest of the repository was waiting for them |
| 0020 | A hidden native control is never painted | Paint on a clipped pixel is invisible to review and to screenshots, and one engine ended the page over it |
| 0021 | A dialog overlay is not a combobox | The combobox opening keys were declared for four kinds that hold no options, and no renderer implemented them |
| 0022 | A theme expresses its own colour model | Two themes could not state their own design system, so a brand colour produced white text at 1.85:1 |
| 0023 | A popup is positioned, not dressed | A container that paints is a wrapper around the thing it was meant to present |
| 0024 | An author-time check calls the parser | The contract already knows what is wrong with a document; an editor check that says so again is a second answer that drifts |
| 0025 | A tag publishes, and nothing else does | A release pipeline whose publish step was a dry run stayed green for four versions while npm served none of them |
| 0026 | A row exists because it was declared | A collection keyed by data, where what is mounted must not decide what exists |
| 0027 | A register and its summary are both checked | A maintainer’s defect register and the page consumers read, held to the same statuses |
| 0028 | A status sentence names a version | One “pre-1.0” line over a workspace whose packages have never shared a maturity |
| 0029 | A widget does not repair the model | A select erased a value it could not render, and the data that would have let a person fix it went with it |
| 0030 | A declared fact survives composition | compose(required(), …) produced a field that was not required, silently, and three copies of one rule disagreed |
| 0031 | A field name is a path, in a schema as everywhere else | A schema keyed by "shipping.city" described a shape no read could produce, so every flattened document mounted into a form that threw on getValue() |
| 0032 | A computed is a function of its inputs | The vanilla graph allowed a signal write inside a computed and Angular refuses it, so shared code could pass every test on one adapter and throw on another |
| 0033 | One engine in the tree | Exact sibling pins installed @modyra/core twice after a partial release, and a required() from one engine was not required to the other |
- ADR 0034: A draft is not a linked signal — a value derived from a handle is a computed; a draft resets on the event that starts it, never on its source
- ADR 0035: The colour arithmetic lives with the themes —
color-utilsandtheme-compilership with the stylesheets they generate, measured to be a leaf with no edge either way - ADR 0036: The UI contract lives in one package — icons, keyboard policy and the option filter move to
@modyra/widgets, which had been importing them sideways from the engine - ADR 0037: A vocabulary does not belong to a parser — the seventeen field kinds were the property of the JSON reader that happened to declare them; a shared vocabulary lives in a leaf owned by nobody who uses it
- ADR 0038: An adapter does not redeclare what it derives — narrowing an upstream type for a framework’s signals is legitimate; restating its members is drift with a delay
- ADR 0039: A breaking change shipped as a patch — eighteen subpaths removed at
2.1.2 → 2.1.3, why that was bounded rather than habitual, and the complete migration table - ADR 0040: A collection owns its subtree — nested collections: gates compose along the whole chain, ownership is explicit, and the eight semantics decided before a line of runtime
- ADR 0041: History crosses structural changes — undo acts on the value as it is now: a declared, removed or renamed row is undoable the moment it happens, at any depth; only the value is restored
- ADR 0042: An adversarial suite attacks from outside —
battle-tests/consumes published entry points only and exists to falsify public claims: every battle cites a registered claim, proves it attacked, and writes a replayable artefact when it breaks something - ADR 0043: A collection nests without a limit — an array may hold an array, a form may nest as deep as it needs, and a document is bounded by the caller rather than by a number; supersedes ADR 0040’s one-positional-level rule
- ADR 0044: A binding belongs to the row — what a control said about a cell travels with the row across a rename or a move, as its value and its marks already did
- ADR 0045: A declaration is all or nothing — a row whose value raises while it is read is not declared; a row reads the object it was given, prototype chain included; a schema is read by its own properties
- ADR 0046: An adapter states no less than the engine — a capability the engine gains ships only when every package that restates it has it, checked by a consumer program rather than by a green suite; a nested collection’s value has the same type as a top-level one
- ADR 0047: An expression reads what a field could name — a document’s predicate passes the engine’s path guard and answers from the value’s own properties;
""stays the root reference - ADR 0048: A panel does not print what it masks — a masked field’s value is taken out of the errors beside it, and a snapshot describes a file rather than handing it over
- ADR 0049: A released custodian owes no focus —
release()ends the borrow, so a widget being torn down places no focus; a named target is still honoured, and the fallback keeps the case it was written for - ADR 0050: A document cannot make the form stop answering — a pattern whose shape backtracks exponentially is refused like one that will not parse, and the field survives the refusal
- ADR 0051: An option is recognised by what it holds —
oneOfcompares an object option by its members, so a draft’s round trip is not tampering, and every forgery it refused it still refuses - ADR 0052: A widget announces only the states it has —
readonlyleaves the kinds whose contract never had it, in both halves, andaria-checkedholds one of the three values the standard allows - ADR 0053: A widget id is refused where it is used, not only where it is asked about — the part-id builders throw on an id that cannot be referenced; the joining factory does not, and nothing is repaired silently
- ADR 0054: A list shows the choice it will not erase — an option is keyed by what it holds, a survivor keeps the label it was painted with and gets a part, and a radio group stops being the exception
- ADR 0055: A runtime that cannot recompute is not the one to run on — Solid’s server build freezes every derived value and reported an invalid form as valid; the adapter probes the graph and falls back to one that answers
- ADR 0056: A project file does not decide what the generated module does — an operand outside the expression vocabulary was printed unquoted into generated source; refused at the compiler and reported where the project is read
- ADR 0057: An argument is refused where it arrives — seven public entry points took a value they could not use and left the form to fail later; the reactive setters, the whole-value write and the initial are checked at the call
- ADR 0058: A rename moves a key, not a row — a renamed row was appended, and the value and the handle kept two different orders for one list
- ADR 0059: A step of history is a state the form was in — a bulk write cost one undo per row and a restored row came back last, so the path back passed through states the form was never in
- ADR 0060: A refusal reaches somebody — three spellings of a server’s refusal were dropped by the guard that drops a hostile path, so a person saw nothing and believed it went through
- ADR 0061: A rule that says nothing says nothing — the validator everybody writes has no
else, returnsundefined, and made the form unreadable from the first question asked of it - ADR 0062: The form says what no field can — three renderers had nowhere to show a refusal that names no field, which made it a missing part rather than three oversights
- ADR 0063: A value a control cannot read stays where it can be corrected —
14:30typed into a 12-hour picker was erased with nothing said; the judgement moves into the controller and the entry is kept and explained - ADR 0064: A typed form refuses a path it does not declare — one transposed letter attached a rule nothing could satisfy and the Submit button stopped working, with nothing said
- ADR 0065: What is said about a path is said about what is under it — the three interactivity setters reached only leaves, so a section a consumer excluded stayed editable and stayed in the payload
- ADR 0066: A bound beside the field is a rule — two spellings of a limit rendered identically and only one was enforced, so a tampered draft outside the bound was valid and submittable
- ADR 0067: A track spans what the field holds — a slider with no declared bound drew a track ending at 100 and put the thumb there for a value of 150, in both renderers, each having invented the default separately
- ADR 0068: A draft does not go backwards — a tab that had been open a while replaced a newer draft and stamped it with an earlier time, so the one field a later reader could use said the opposite
- ADR 0069: An unreadable condition does not open — a misspelled operator evaluated to
trueand showed a section to everyone, and a condition’s pattern carried no cost gate - ADR 0070: A server is asked about a value the field accepts — a tax id typed group by group sent four requests for values
minLength(11)already rejects, andwhenloses because it restates a bound the field declared - ADR 0071: A document is answered the same in both its shapes — the tree parser dropped fields in silence where the flat list reported them, and
strictapproved a document whose only field it had discarded - ADR 0072: A positional change set carries its whole list — a compacted list of changed rows said nothing about where they were, so a server applying it by position wrote the wrong row
- ADR 0073: A verdict a person can see is one the form counts — a picker showed an unreadable entry as an error and the form called itself submittable, sending the field empty
- ADR 0074: A file the field turned away is something the page says — the transition reported what it refused, no renderer showed it, and no message table had a word for it
- ADR 0075: A popup that opens says so — the lifecycle policy answered
announcefor every open and close, and two of the three renderers read neither - ADR 0076: A state belongs to something that can be in it — the one opener the contract gave no role wore
aria-invalidandaria-requiredwhere nothing could read them - ADR 0077: The opener a contract names is the one a keyboard reaches — two date inputs claimed the popup’s state while the part that opens it was not a tab stop, and lit’s pickers had no keyboard door at all
- ADR 0078: A widget announces the refusal it makes — twelve kinds refused every change while read-only and said nothing, because the rule that made silence right had since been implemented
- ADR 0079: A rule a document writes is a rule the form keeps — the parser guarded
rulesas behaviour and nothing applied one, so a document saying to disable a field produced a form that sent it - ADR 0080: A path is an instruction a row’s shape can refuse — one extra segment in a draft key built a row and a member no document declared, and the form called itself ready
- ADR 0081: A secret is excluded by the name a person writes —
excludematched one exact path, so the guide’s own example — a card number in a list — was the case it could not answer - ADR 0082: A commit word answers for the control a person types in — a range is neither
livenorconfirm, and a colours field has two controls that commit differently - ADR 0083: A form reports what it could not do — the diagnostics vocabulary was published and nothing took a sink, so a check that stopped running was invisible on every surface
- ADR 0084: A contract version names the anatomy — parts were removed and an element changed while the number that exists to say so stayed at 1
- ADR 0085: A name a package exports belongs to one function — two hooks shipped under
useMdyField, andexport *yielded to the local one in silence - ADR 0086: A derived form starts at an empty its schema accepts — a bridge seeded a sentinel its own schema refused, so one emptiness got two answers and
requiredcontradictedvalid - ADR 0087: A target answers with everything it knows about the project — three code targets called a project compatible that the contract compiler reports errors on, and said nothing about a kind they cannot draw
- ADR 0088: A draft is not replaced by one belonging to another form — two live forms on one key meant the last save deleted the other’s work, and nothing said so
- ADR 0089: A field that says it is a secret is treated as one — the contract’s
sensitiveflag reached no protection, so a secret was autosaved in clear and printed in the panel - ADR 0090: A rule with a bug in it is a verdict, not an outage — a validator that threw made every later read of the form throw, and a predicate that threw stopped the form being built
- ADR 0091: A form that has ended answers with one voice — a destroyed form called itself submittable with nothing to submit, and a late write reached one surface of two
- ADR 0093: A field that leaves play takes its overlay with it — a rule took a field out of play and left its calendar open, expanded, and answering nothing
- ADR 0094: One question about emptiness, one answer —
requiredrefused a valueisEmptycalled filled, so a rule opened a section the form was still refusing to submit - ADR 0095: A flat pair carries the shape of a row — a collection with no rows had no template, so a form rebuilt from the flat pair accepted a row and held nothing
- ADR 0096: A row the form was not built with is a change —
reset()threw a new row away whilegetChanges()reported nothing, so a patch never carried the rows a user made - ADR 0097: A member nobody declared is reported — the published schema closes every object and the parser closed none, so the one check a stored document meets said nothing
- ADR 0098: A fixture’s context lives beside it — v4’s conditions read what the host supplies, and the shared corpus had no way to say what that is
- ADR 0099: A password is said to be one — the published description of a password was the description of a text field, so masking was private knowledge in every adapter
- ADR 0100: A position is an identity — a fully disabled row left the payload, so every row after it was sent at a position it does not have
- ADR 0101: A collection asks for its own rows — a question scoped to a path was answered by a scan of the whole form, so declaring rows cost more the more rows there were
- ADR 0102: A change set is a payload too — a positional list was carried whole out of the form value, so a disabled cell left through the change set that a submit withheld
- ADR 0103: A patch names cells, in a list too — a partial positional row rebuilt the cells it did not name from the schema, so a form could not read the change set its own door produced
- ADR 0104: Change is decided by
Object.is— the conformance gate accepted a runtime whose default equality was===, so a field written-0over0re-rendered nothing - ADR 0105: One handle registry per realm — a module-level registry is per copy, so two copies of the engine in one tree turned the cross-runtime guard off
- ADR 0106: A door named for a contract reads it — the Angular component was named for the dynamic contract and took only the parsed half, so a document’s rules vanished and each host wrote the parse step again
- ADR 0107: A draft is read by the form that wrote it — the write side compared the recorded form shape and the read side did not, so the draft the writer refused to replace was the one the reader restored
- ADR 0108: A seed a theme can be read on — the default primary sat in the 13% of sRGB where the rule picks light text that cannot reach AA, so the filled button shipped at 4.09:1
- ADR 0109: An element nobody bound says so — the element surface was the one published door that failed in silence: an empty custom element, no control, and nothing said
- ADR 0110: A promise is declared where the popup is —
aria-haspopupwas a literal at fourteen openers with no common source, so two kinds promised a popup neither renderer opened - ADR 0111: A selector cannot close the sheet it is written into — the theme compiler guarded a selector against escaping its CSS rule and not against escaping the
<style>block around it - ADR 0112: A radio group has nowhere to jump —
HomeandEndwere declared for every kind that navigates options, and three renderers independently declined to implement them on a radio group - ADR 0113: A field name cannot break the value it is in — a field named
toStringshadowed the method every string conversion goes through, so${value}threw in the consumer’s own code - ADR 0114: A dev-time advisory is pinned, not waived — twenty-three alerts across eight packages that no published tarball carries, pinned inside their own majors because an unbounded override took
fast-uriacross one - ADR 0115: An hour carries the half of the day it is in — a 24-hour picker could not be moved off the half of the day it opened on, because the one seam that writes took 1–12 while every other surface spoke 0–23
- ADR 0116: One clock in every renderer — three renderers each wrote down their own default format, so one document could render a different clock in each adapter
- ADR 0117: A row is not a target — a boolean’s wrapper was a
<label>, so the empty remainder of the row toggled the field, and removing it left the drawn box unclickable - ADR 0118: One cell says whether a popup is open — the contract closes a popup whose field leaves play by writing the controller’s
open, and Angular painted a cell of its own - ADR 0119: An overlay’s boundary is the contract’s, not the renderer’s — four renderers each answered “is this press inside the popup” and three could get the portalled part wrong in silence
- ADR 0120: A picker that offers only some of the times — a granularity as data, refused by name where it is declared, obeyed by the face, the arrows, the typing and the drag alike
- ADR 0121: A legitimate value must not be indistinguishable from its own absence — four defects in one evening shared a guard that asked whether a value was usable when it needed to ask whether it was there
- ADR 0122: Tab moves inside a popup that has controls of its own — Tab dismissed every overlay, so a timepicker’s confirm button was unreachable and its only commit path was a pointer
- ADR 0123: A default is published, or it is copied — four renderers each spelled the clock default out and two had already drifted, while the view a picker opens in was a capability no document could reach
- ADR 0124: The public pitch is a single claim set — three surfaces answered “what is Modyra” three ways, and the positioning that could have stopped it lived in an untracked directory
- ADR 0125: A chip strip is one thing to a keyboard — twelve choices cost twenty-six tab stops, and reordering was being built on the strip that the fix for it has to rebuild
- ADR 0126: Focus is placed, not dropped — removing a chip returned a keyboard user to the top of the page, and the pin that found it asserted a threshold rather than a rule
- ADR 0127: A strip that scrolls, against the published practice — an outside review ranked the scrolling row last but one and called it a deliberate 1.4.10 departure, and the one-row-per-control rule is why it was taken anyway
- ADR 0128: A chip is one thing, not a cell — the APG’s composite pattern is grid, and the design had already removed the children grid exists to reach
- ADR 0129: One way back, not three — a clear-all with no undo is worse than no clear-all, and an undo that covers the loudest action and not the quiet ones is worse than none
- ADR 0130: A popup outlives the box it opens from — superseded: the clipping it was built on was a rectangle compared against a rectangle, and every popup is
position: fixed - ADR 0131: A rectangle outside a box is not a clipped one — the defect did not exist; the battle written to prove it now pins the property instead
- ADR 0132: A part’s name says what it is for, its role says what it is — one kind took its role as its part name, and a consumer asking the other kind for it got
undefined - ADR 0133: A chip’s mark is drawn, never written — the argument that decided it turned out to be false, and the decision stands on the two reasons that were not why it was taken
- ADR 0134: The projection decides an id, and every renderer applies it — an
aria-labelledbythe contract emits resolved in one renderer and pointed at nothing in another - ADR 0135: An id is a function of the document, not of mount order — two renderers minted ids from a counter, so the same declaration got a different id depending on what was mounted first
- ADR 0136: A version one runtime accepts is a version all of them accept — TypeScript accepted a version Rust and Java refuse, so a document built a form in one runtime and did not exist for the other two
- ADR 0137: A row that wraps where one line stops being a layout rule — the scroll departure was paid for with an announcement no role could carry, and reflow was owed to a sighted person all along
- ADR 0138: A chip is an item in a list, not a number in a range — the quantity chip gives up the spinbutton published practice prescribes, because a role that carries a value cannot carry a position
- ADR 0139: A select has two shapes, and one renderer only ever draws one of them —
searchableswitches between a native control and a combobox, the contract describes only the combobox, and plain never leaves it - ADR 0140: A popup that holds a draft is a dialog, and the catalogue says so — the kind declares the popup’s role, modality is a separate property from it, and a draft’s dialog is named by the field’s label
- ADR 0141: An id built from a value escapes it — a published id is a handle a consumer may select with, so caller data is hex-escaped into it rather than embedded raw
- ADR 0142: A field that holds controls is not a control — the box becomes a container, the chip strip and the opener become siblings, and a press stops being decided by the length of a word
- ADR 0143: A widget box inside the shell every kind sits in — one part name means one element, so a kind that draws two boxes declares two parts and its parts hang off the inner one
- ADR 0144: A slot that is always there — the way back reserves its line whether or not it is offered, because a cost that moves is one nobody can learn
- ADR 0145: A dial that repeats what a box already says — a redundant graphic is hidden from assistive technology, and what it announced moves to the control a person can reach
- ADR 0146: A form carries its own scope — every form has an id scope whether or not anybody asked, because the person who pays for a collision is not the one who reads the warning
- ADR 0147: The cluster at the end of a field — the undo joins the controls it is the opposite of, in a slot reserved so nothing slides under a thumb
- ADR 0148: A strip a browsing reader can reach — a listitem does not switch a screen reader’s mode, so the strip’s whole keyboard model never reached somebody who arrived by browsing
- ADR 0149: A form answers its own reset by returning to the initial values
- ADR 0150: What is submitted is what was on screen — the browser writes into a person’s form and tells nobody, so the field showed one value while the form held another
- ADR 0151: The floor is Baseline widely available, and everything below it is declared — the repository never said which browsers it works in, and arrived here one rule at a time
- ADR 0152: A form built with these controls submits, and the payload carries the field’s own names — no control wrote a
name, so a native submit sent nothing at all - ADR 0153: A control’s accessible name is what it is for, never what it holds — the check asked a chooser to answer to the grey word inside it, so it failed the renderer that was right
- ADR 0154: A part’s classes read the same from the record and from the accessor — two published surfaces gave opposite answers about the same part, and neither reader was misreading
- ADR 0155: A press completes on the release — one renderer opened a list while the button was still down, so the gesture a person uses to take a tap back did nothing
- ADR 0156: A panel answers both doors — a list opened with the mouse answered no key, because a press leaves focus where it landed and it landed on nothing
- ADR 0157: A key that waits for something to have happened — a key that does nothing because the moment is wrong is indistinguishable from one nobody implemented
- ADR 0158: A thirteenth that is a door — a field that takes every colour offered twelve, and neither of its two routes could see the disagreement
- ADR 0159: The filled square is what opens the panel — the most recognisable shape on the field did one thing in two renderers and another in the third, and a caret beside it was a second command for one act
- ADR 0160: A form nests six levels deep, and the limit is about people — nesting costs the machine nothing measurable, which is why the reason had to be written down, and one of the two doors was not enforcing it
- ADR 0161: The nesting limit was on the wrong axis — the argument was about conditionality and the constant limited arrangement, which was unguarded on the axis it defended
- ADR 0162: A renderer writes no class of its own — five undeclared classes outlived the stylesheet that used them, exempted from the conformance gate by an option the gate’s green result never showed
- ADR 0163: One live region for the page — eight adapters each named a region of their own; two regions speaking at once are read in an order nothing specifies, and a queue can only stand in front of one
- ADR 0164: When an optional part is there — 193 optional nodes and not one said when; the error container is reserved under fields that can fail, and the reservation stays after the correction
- ADR 0165: Empty is not wrong —
aria-invalidis a verdict on an act, not a state; a required field nobody has reached contains nothing, and a value that arrived already wrong speaks at once - ADR 0166: A key is data, not syntax — a key derived from a value is compared, never interpolated into a selector, and the order the chips are in is asked of the contract by name
- ADR 0167: Reading a form is not declining it — a form speaks when the value has been touched, never when only focus has; a panel is inside its field’s focus scope wherever it is rendered
- ADR 0168: A gesture that adds, and a gesture that removes — a gesture that adds is refused under a held accelerator, one that removes is honoured whatever is held, and the rule is declared rather than coded
- ADR 0169: Which presence conditions owe a resolver — a condition owes one when two renderers could disagree from the same state; where the answer restates an input the renderer holds, a resolver is ceremony
- ADR 0170: A caption nobody wrote — the caption element always exists so every reference resolves, carries the field’s key where a document wrote none, and is taken out of sight rather than out of the tree
- ADR 0171: Absent for configuration, disabled for state — a control that is part of a field is always present and announces when it cannot act; absence is for what a configuration left out
- ADR 0172: The trailing column carries one thing — the field’s trailing edge holds only the affordance every kind has; commands about the value stand with the value, and a glyph-only button is named by its action
- ADR 0173: A position may depend on the field, never on the value — a control that stands beside a variable-length value moves under the hand that is reaching for it; the commands return to the trailing edge with the opener outermost and a full target of space between them
- ADR 0174: A key means what the part under it means — the space bar is a character in a text box, “this one” on a highlighted day or option, and a press on a button; the meaning is the part’s, not the kind’s
- ADR 0175: The caption names the group, each control names itself — one caption over two boxes named both boxes the same thing; the caption names the pair and each box says its own role
- ADR 0176: A select is two shapes, and the contract says which — the native chooser and the combobox are variants; read as one anatomy the contract owed every select the combobox’s parts
- ADR 0177: The second door, and what the contract declines to say — a pointer’s second way into a panel is declared; an optional part with no condition is the renderer’s choice, and a control named by a reference or by the words is one answer
- ADR 0178: A date a person can read aloud — the display names its month in the reader’s language, the value stays ISO, input accepts widely and echoes back what it understood
- ADR 0179: Where the keyboard stands when a list opens — focus goes where the next input will arrive, and how the panel was opened says what kind that is; the cursor is primed on the first value already chosen
- ADR 0180: A container held open under a field that can fail — the message’s container is present from the first paint, so the page does not move under a person and one reference stands; a named empty container is not a dangling one — amended: the complement, when an empty container may go, and why an empty flex child is still charged a gap
- ADR 0181: A field that holds a paragraph is three lines tall, and says so in lines — two lines read as a one-line field that came out wrong; and a length stops meaning “three lines” the moment a person enlarges their text, so the size is stated in lines
- ADR 0182: Where the text a person types begins is declared once — the inset is declared on the inliner and on the control and both apply, so one renderer pays it twice; declared once, applied once, at the number two renderers already draw — amended: a colour field hides a native picker ahead of its hex box, so a rule about “the control inside the wrapper” reaches an element nobody writes in; that and two ways a correct cascade rule loses
- ADR 0183: A number that is reserved, and a debt that is stated — the diff says major and the release ships as a minor, because the number 3 is reserved for a narrower surface than this one; the warning the version withholds is paid in a BREAKING section, and if that section ever thins the number has to move instead
- ADR 0184:
okis false as soon as something was lost — a parse that graded a diagnostic an error and reported success in the same breath let a dropped condition mount as a field with no condition;oknow means what its name says, and lenient still returns what it read - ADR 0185: A word the language gains takes a number —
integercould be written by hand and not declared, and the schema gate refused the obvious repair: all three versions are published, so the word takes v5, and a member’s arrival is declared once where both the parser and the audit read it - ADR 0186: The corpus declares what it expects, and who must have read it — three documents sat unread by both SDK readers and neither suite went red, because a fixture nobody reads cannot fail; a document now declares its verdict beside itself and every reader must be able to name it
- ADR 0187: A baseline is moved by what it photographs — a per-widget image is hostage to fractional layout above it, so the plain suite photographs the bench and the page written to be read keeps no baseline
- ADR 0188: A panel that cannot say nothing — an inspection panel whose every datum carries whether it was read, because a blank cell claims a value is absent when it may mean nobody looked; and what it inherits from 0048, 0089 and 0099 rather than deciding again
- ADR 0189: A second reader of the same question — a question the contract can answer has one reader; two that are never run together are two beliefs, and putting the panel’s and the bench’s on six documents found a precedence inversion latent under the assertion it sat beneath
- ADR 0190: A verdict that has not happened — an asynchronous rule that has not answered is
unknown, not valid and not invalid; a restore re-derives rather than installs; and a runtime that has not declared the capability is refused by name - ADR 0191: A gate nobody runs — the conformance kit’s browser half was in no workflow; its eleven findings against plain were all its own, and a probe that does not assert its focus landed cannot tell a press that went nowhere from a widget that ignored it
- ADR 0192: A debt that cannot be paid where it is incurred — linux baselines are recorded from a pushed head, so the commit-time check announces the debt and names the run instead of refusing the commit it cannot let through
- ADR 0193: A rewrite is not a deletion — the filter matches by shape because a censor that names what it censors has published it, excluded names live in the ignore file that is not itself versioned, and a force-push removes an object from reachable history without deleting it from the remote
- ADR 0194: A class that belongs to no kind — the class contract has three doors; a part costs a semantic and a presentation class costs none, and a survey that asks two doors of three invents work
- ADR 0195: A list that arrives after the control is on screen — the option list is configuration in React and a call everywhere else, so a React select closes when its list is replaced and the others do not
- ADR 0196: A filter says what may be added, never what is already held — the widening ran on both sides of the host’s filter, so a held value it refuses vanished on one route and survived on the other; the held value is always offered
- ADR 0197: A panel opens on what it is for — the primary operable unit takes focus; five kinds already did it privately and the sixth had three answers
- ADR 0198: An action in a panel is one a key can reach — the predicate was narrower than the sentence beside it, and one panel’s action was pointer-only for years
- ADR 0199: The view a calendar is showing is one a key can change — the arrows move within a view and nothing declared a door between them; the accelerator opens it, chosen by measurement
- ADR 0200: A lint rule is loosened only to keep an intention already stated — a red check nobody runs and a green one bought by loosening protect equally; each exemption names the sentence it keeps
- ADR 0201: The custom properties nothing reads are removed, and seven that look alike are kept — a var() is not the only way a property is surface: seven are set by a theme rather than read by the library
- ADR 0202: What repeats is derived from the anatomy, not listed by name
- ADR 0203: An audit that could not ask is not an audit that found nothing — a transport error and a security finding left through the same exit code; the asymmetry is announce on a push, refuse at the release boundary
- ADR 0204: A dependency the barrel cannot load without is not optional — a single entry point resolves
react-domfor everyone who imports it, so the peer is required; the separate headless entry point waits for a consumer who wants it - ADR 0205: A document declares in two channels, and only one of them validates — rules judge a value,
configdraws the control;stepis an affordance that gives way to the value, so it is not a rule - ADR 0206: A field that leaves the scene closes what it holds open — the third species of closing, stated so it stops depending on where a renderer draws its panel; ADR 0131’s freedom is untouched
- ADR 0207: A part that shows something is told what, in a closed vocabulary — a slider’s number, a file field’s prompt, a swatch’s colour: projected in two members and no more, because a free channel is a surface no check can defend
- ADR 0208: A value of the wrong shape is a verdict, not a crash
- ADR 0209: A literal cannot carry a position — a door that depends on an observation made before it is called takes the observation, not a boolean asserting someone made it; correct prose, followed internally and required of nobody, is what let this through
- ADR 0210: A promise points at what keeps it —
aria-haspopupclaims a role andaria-controlssays which element has it: the reference names the sub-region carrying it, not the panel around it - ADR 0211: An argument of the wrong shape is a defect — a value is a verdict and an argument is a code defect: two audiences, two policies, and a wrong shape that never passes in silence
- ADR 0212: What a calendar is called — the grid is named by the month it shows, through the visible heading rather than a second copy of it; the panel is named by the field, and no element carries two naming channels
- ADR 0092: A condition travels with the form —
whenandasyncWhenwere closures, so a schema carrying one was not data and the document half could not say what the typed half said
Security-relevant records
Section titled “Security-relevant records”Start here for a security review: 0007 (untrusted documents are never executed), 0009 (the trust boundary and the draft storage exposure), 0010 (which of those properties are held by a test rather than by prose), 0024 (the same refusal to execute a document, at the editor boundary), 0025 (the registry credential, and why no publish token is stored), 0111 (the one place a caller’s string reaches a stylesheet, and which container it is held inside).
Changing a record
Section titled “Changing a record”A decision that no longer holds is superseded, not edited into agreement with the present. Write
the new record, and set the old one’s status to Superseded by [ADR NNNN]. The reasoning that was
correct under the old constraints is what makes the new decision legible.
A decision that still holds but has grown may be amended in place, with the amendment marked as such — 0005 carries one.