@oods/component-contracts 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -6,7 +6,7 @@ var component_intake_v1_default = {
6
6
  kind: "component-intake",
7
7
  baselineCommit: "ae560bc22969c1fd81336730be4330c9115fc316",
8
8
  planningCommit: "8ce349076e7e3ba3f0b2f3f667d4fbb5c6a4b63b",
9
- controllingObligationDenominator: 112,
9
+ controllingObligationDenominator: 114,
10
10
  countRule: "Derived from the unique, deterministically sorted rows array; never from an independent counter.",
11
11
  rows: [
12
12
  {
@@ -937,6 +937,38 @@ var component_intake_v1_default = {
937
937
  "traits/visual/Colorized.trait.yaml"
938
938
  ]
939
939
  },
940
+ {
941
+ id: "Combobox",
942
+ displayName: "Combobox",
943
+ baselineMetadata: {
944
+ categories: [
945
+ "primitive"
946
+ ],
947
+ tags: [
948
+ "autocomplete",
949
+ "combobox",
950
+ "field",
951
+ "filter",
952
+ "form",
953
+ "input",
954
+ "interactive",
955
+ "primitive",
956
+ "select"
957
+ ],
958
+ contexts: [
959
+ "form"
960
+ ],
961
+ regions: [
962
+ "form",
963
+ "main"
964
+ ]
965
+ },
966
+ intakeEvidence: [
967
+ "packages/component-contracts/src/contracts.ts#Combobox",
968
+ "packages/mcp-server/src/render/component-map.ts#renderCombobox"
969
+ ],
970
+ addedBy: "s223-m02; decision #2527 ruling 11"
971
+ },
940
972
  {
941
973
  id: "CommunicationDetailPanel",
942
974
  displayName: "CommunicationDetailPanel",
@@ -1922,6 +1954,37 @@ var component_intake_v1_default = {
1922
1954
  "traits/behavioral/Searchable.trait.yaml"
1923
1955
  ]
1924
1956
  },
1957
+ {
1958
+ id: "SegmentedControl",
1959
+ displayName: "SegmentedControl",
1960
+ baselineMetadata: {
1961
+ categories: [
1962
+ "primitive"
1963
+ ],
1964
+ tags: [
1965
+ "choice",
1966
+ "field",
1967
+ "form",
1968
+ "input",
1969
+ "interactive",
1970
+ "primitive",
1971
+ "radio",
1972
+ "segmented-control"
1973
+ ],
1974
+ contexts: [
1975
+ "form"
1976
+ ],
1977
+ regions: [
1978
+ "form",
1979
+ "main"
1980
+ ]
1981
+ },
1982
+ intakeEvidence: [
1983
+ "packages/component-contracts/src/contracts.ts#SegmentedControl",
1984
+ "packages/mcp-server/src/render/component-map.ts#renderSegmentedControl"
1985
+ ],
1986
+ addedBy: "s223-m02; decision #2527 ruling 10"
1987
+ },
1925
1988
  {
1926
1989
  id: "Select",
1927
1990
  displayName: "Select",
@@ -3228,9 +3291,9 @@ var component_reconciliation_proposed_v2_default = {
3228
3291
  baselineCommit: "a5638cf819bdadb86e2336c4aabe9b2184699c13",
3229
3292
  planningCommit: "8ce349076e7e3ba3f0b2f3f667d4fbb5c6a4b63b",
3230
3293
  status: "proposed-awaiting-approval",
3231
- controllingObligationDenominator: 112,
3294
+ controllingObligationDenominator: 114,
3232
3295
  approvedRuntimeCensus: null,
3233
- proposedRuntimeCensus: 112,
3296
+ proposedRuntimeCensus: 114,
3234
3297
  rows: [
3235
3298
  {
3236
3299
  id: "AddressCollectionPanel",
@@ -3870,6 +3933,25 @@ var component_reconciliation_proposed_v2_default = {
3870
3933
  implementationStatus: "implemented-evidence-complete",
3871
3934
  compatibilityNote: "Retain the named public ID and existing HTML discovery contract. Governed framework implementation and measurements are linked; classification remains a proposal."
3872
3935
  },
3936
+ {
3937
+ id: "Combobox",
3938
+ proposedClassification: "native",
3939
+ approvalState: "pending-approval",
3940
+ evidence: [
3941
+ "packages/mcp-server/src/render/component-map.ts#renderCombobox",
3942
+ "packages/components-react/evidence/react-readiness.v1.json#Combobox",
3943
+ "packages/components-vue/evidence/vue-readiness.v1.json#Combobox",
3944
+ "packages/component-contracts/src/contracts.ts#Combobox"
3945
+ ],
3946
+ implementationStatus: "implemented-evidence-complete",
3947
+ proposedResolution: {
3948
+ surface: "react+vue+html",
3949
+ implementation: "Combobox",
3950
+ source: "packages/component-contracts/src/contracts.ts",
3951
+ publicIdRetained: true
3952
+ },
3953
+ compatibilityNote: "New public identity added by decision #2527 (ruling 11). Governed framework implementation and measurements are linked; classification remains a proposal."
3954
+ },
3873
3955
  {
3874
3956
  id: "CommunicationDetailPanel",
3875
3957
  proposedClassification: "recipe",
@@ -4583,6 +4665,25 @@ var component_reconciliation_proposed_v2_default = {
4583
4665
  implementationStatus: "implemented-evidence-complete",
4584
4666
  compatibilityNote: "Retain the named public ID and existing HTML discovery contract. Governed framework implementation and measurements are linked; classification remains a proposal."
4585
4667
  },
4668
+ {
4669
+ id: "SegmentedControl",
4670
+ proposedClassification: "native",
4671
+ approvalState: "pending-approval",
4672
+ evidence: [
4673
+ "packages/mcp-server/src/render/component-map.ts#renderSegmentedControl",
4674
+ "packages/components-react/evidence/react-readiness.v1.json#SegmentedControl",
4675
+ "packages/components-vue/evidence/vue-readiness.v1.json#SegmentedControl",
4676
+ "packages/component-contracts/src/contracts.ts#SegmentedControl"
4677
+ ],
4678
+ implementationStatus: "implemented-evidence-complete",
4679
+ proposedResolution: {
4680
+ surface: "react+vue+html",
4681
+ implementation: "SegmentedControl",
4682
+ source: "packages/component-contracts/src/contracts.ts",
4683
+ publicIdRetained: true
4684
+ },
4685
+ compatibilityNote: "New public identity added by decision #2527 (ruling 10). Governed framework implementation and measurements are linked; classification remains a proposal."
4686
+ },
4586
4687
  {
4587
4688
  id: "Select",
4588
4689
  proposedClassification: "native",
@@ -5475,7 +5576,7 @@ var component_capability_ledger_v1_default = {
5475
5576
  schemaVersion: "1.0.0",
5476
5577
  kind: "component-capability-ledger",
5477
5578
  generatedAt: "2026-09-11T05:30:00Z",
5478
- controllingObligationDenominator: 112,
5579
+ controllingObligationDenominator: 114,
5479
5580
  approvedRuntimeCensus: null,
5480
5581
  source: "refresh_structured_data.py#project_measured_surfaces",
5481
5582
  rows: [
@@ -8184,6 +8285,77 @@ var component_capability_ledger_v1_default = {
8184
8285
  }
8185
8286
  }
8186
8287
  },
8288
+ {
8289
+ id: "Combobox",
8290
+ proposedClassification: "native",
8291
+ reconciliationState: "proposed-awaiting-approval",
8292
+ surfaces: {
8293
+ contract: {
8294
+ state: "versioned-v1",
8295
+ evidence: [
8296
+ "packages/component-contracts/src/contracts.ts#Combobox"
8297
+ ]
8298
+ },
8299
+ metadata: {
8300
+ state: "available",
8301
+ evidence: [
8302
+ "packages/component-contracts/registry/component-intake.v1.json#Combobox"
8303
+ ]
8304
+ },
8305
+ html: {
8306
+ state: "mapped",
8307
+ evidence: [
8308
+ "packages/mcp-server/src/render/component-map.ts#renderCombobox"
8309
+ ]
8310
+ },
8311
+ react: {
8312
+ state: "implemented-evidence-complete",
8313
+ evidence: [
8314
+ "packages/components-react/evidence/react-readiness.v1.json#Combobox"
8315
+ ]
8316
+ },
8317
+ vue: {
8318
+ state: "implemented-evidence-complete",
8319
+ evidence: [
8320
+ "packages/components-vue/evidence/vue-readiness.v1.json#Combobox"
8321
+ ]
8322
+ },
8323
+ generatedConsumer: {
8324
+ state: "unavailable",
8325
+ evidence: [
8326
+ "artifacts/product-reality/sprint-193/m07/runtime/runtime-cells.v1.json"
8327
+ ],
8328
+ reason: "No current runtime cell places this component; historical receipts do not establish current coverage."
8329
+ },
8330
+ accessibility: {
8331
+ state: "verified",
8332
+ evidence: [
8333
+ "artifacts/product-reality/sprint-223/m02/combobox/react-measured.json#Combobox",
8334
+ "artifacts/product-reality/sprint-223/m02/combobox/vue-measured.json#Combobox",
8335
+ "packages/components-react/evidence/react-readiness.v1.json#Combobox",
8336
+ "packages/components-vue/evidence/vue-readiness.v1.json#Combobox"
8337
+ ]
8338
+ },
8339
+ theme: {
8340
+ state: "verified",
8341
+ evidence: [
8342
+ "artifacts/product-reality/sprint-223/m02/combobox/react-theme/report.json#Combobox",
8343
+ "artifacts/product-reality/sprint-223/m02/combobox/vue-theme/report.json#Combobox",
8344
+ "packages/components-react/evidence/react-readiness.v1.json#Combobox",
8345
+ "packages/components-vue/evidence/vue-readiness.v1.json#Combobox"
8346
+ ]
8347
+ },
8348
+ interaction: {
8349
+ state: "verified",
8350
+ evidence: [
8351
+ "artifacts/product-reality/sprint-223/m02/combobox/react-measured.json#Combobox",
8352
+ "artifacts/product-reality/sprint-223/m02/combobox/vue-measured.json#Combobox",
8353
+ "packages/components-react/evidence/react-readiness.v1.json#Combobox",
8354
+ "packages/components-vue/evidence/vue-readiness.v1.json#Combobox"
8355
+ ]
8356
+ }
8357
+ }
8358
+ },
8187
8359
  {
8188
8360
  id: "CommunicationDetailPanel",
8189
8361
  proposedClassification: "recipe",
@@ -11235,6 +11407,77 @@ var component_capability_ledger_v1_default = {
11235
11407
  }
11236
11408
  }
11237
11409
  },
11410
+ {
11411
+ id: "SegmentedControl",
11412
+ proposedClassification: "native",
11413
+ reconciliationState: "proposed-awaiting-approval",
11414
+ surfaces: {
11415
+ contract: {
11416
+ state: "versioned-v1",
11417
+ evidence: [
11418
+ "packages/component-contracts/src/contracts.ts#SegmentedControl"
11419
+ ]
11420
+ },
11421
+ metadata: {
11422
+ state: "available",
11423
+ evidence: [
11424
+ "packages/component-contracts/registry/component-intake.v1.json#SegmentedControl"
11425
+ ]
11426
+ },
11427
+ html: {
11428
+ state: "mapped",
11429
+ evidence: [
11430
+ "packages/mcp-server/src/render/component-map.ts#renderSegmentedControl"
11431
+ ]
11432
+ },
11433
+ react: {
11434
+ state: "implemented-evidence-complete",
11435
+ evidence: [
11436
+ "packages/components-react/evidence/react-readiness.v1.json#SegmentedControl"
11437
+ ]
11438
+ },
11439
+ vue: {
11440
+ state: "implemented-evidence-complete",
11441
+ evidence: [
11442
+ "packages/components-vue/evidence/vue-readiness.v1.json#SegmentedControl"
11443
+ ]
11444
+ },
11445
+ generatedConsumer: {
11446
+ state: "unavailable",
11447
+ evidence: [
11448
+ "artifacts/product-reality/sprint-193/m07/runtime/runtime-cells.v1.json"
11449
+ ],
11450
+ reason: "No current runtime cell places this component; historical receipts do not establish current coverage."
11451
+ },
11452
+ accessibility: {
11453
+ state: "verified",
11454
+ evidence: [
11455
+ "artifacts/product-reality/sprint-223/m02/segmented-control/react-measured.json#SegmentedControl",
11456
+ "artifacts/product-reality/sprint-223/m02/segmented-control/vue-measured.json#SegmentedControl",
11457
+ "packages/components-react/evidence/react-readiness.v1.json#SegmentedControl",
11458
+ "packages/components-vue/evidence/vue-readiness.v1.json#SegmentedControl"
11459
+ ]
11460
+ },
11461
+ theme: {
11462
+ state: "verified",
11463
+ evidence: [
11464
+ "artifacts/product-reality/sprint-223/m02/segmented-control/react-theme/report.json#SegmentedControl",
11465
+ "artifacts/product-reality/sprint-223/m02/segmented-control/vue-theme/report.json#SegmentedControl",
11466
+ "packages/components-react/evidence/react-readiness.v1.json#SegmentedControl",
11467
+ "packages/components-vue/evidence/vue-readiness.v1.json#SegmentedControl"
11468
+ ]
11469
+ },
11470
+ interaction: {
11471
+ state: "verified",
11472
+ evidence: [
11473
+ "artifacts/product-reality/sprint-223/m02/segmented-control/react-measured.json#SegmentedControl",
11474
+ "artifacts/product-reality/sprint-223/m02/segmented-control/vue-measured.json#SegmentedControl",
11475
+ "packages/components-react/evidence/react-readiness.v1.json#SegmentedControl",
11476
+ "packages/components-vue/evidence/vue-readiness.v1.json#SegmentedControl"
11477
+ ]
11478
+ }
11479
+ }
11480
+ },
11238
11481
  {
11239
11482
  id: "Select",
11240
11483
  proposedClassification: "native",
@@ -15333,6 +15576,7 @@ var NUCLEUS_COMPONENT_IDS = [
15333
15576
  "ColorStatePicker",
15334
15577
  "ColorSwatch",
15335
15578
  "ColorizedBadge",
15579
+ "Combobox",
15336
15580
  "CommunicationDetailPanel",
15337
15581
  "CycleProgressCard",
15338
15582
  "DatePicker",
@@ -15368,6 +15612,7 @@ var NUCLEUS_COMPONENT_IDS = [
15368
15612
  "RoleAssignmentForm",
15369
15613
  "RoleBadgeList",
15370
15614
  "SearchInput",
15615
+ "SegmentedControl",
15371
15616
  "Select",
15372
15617
  "SortIndicator",
15373
15618
  "Stack",
@@ -15502,6 +15747,11 @@ var componentBehaviors = {
15502
15747
  ClassificationPanel: { "role": "none", "name": { "strategy": "heading", "target": "h1,h2,h3,h4,h5,h6" }, "keyboard": {}, "interaction": "none", "interactionReason": "ClassificationPanel presents content and owns no focusable control or action; authored child actions remain the consumer's responsibility.", "event": [] },
15503
15748
  ColorSwatch: { "role": "none", "name": { "strategy": "none", "target": ":root" }, "keyboard": {}, "interaction": "none", "interactionReason": "ColorSwatch presents content and owns no focusable control or action; authored child actions remain the consumer's responsibility.", "event": [] },
15504
15749
  ColorizedBadge: { "role": "none", "name": { "strategy": "none", "target": ":root" }, "keyboard": {}, "interaction": "none", "interactionReason": "ColorizedBadge presents content and owns no focusable control or action; authored child actions remain the consumer's responsibility.", "event": [] },
15750
+ // s223-m02 (#2527 ruling 11): each trigger starts from the documented example (Canada chosen, the list closed). Tab reaches
15751
+ // the input; typing edits the filter text; Down opens the list at the first option and Up at the last (Japan, disabled,
15752
+ // is never reached); Home and End act on the list a key has opened; Enter picks the active option (France, after three
15753
+ // Downs); and Escape with the list closed clears the field and emits an empty value.
15754
+ Combobox: { "role": "combobox", "name": { "strategy": "label", "target": 'input[role="combobox"]' }, "keyboard": { "Tab": "Move focus to the named native control; an open list closes without picking", "x": "Type to filter the options by label", "ArrowDown": "Open the list and move to the next option", "ArrowUp": "Move to the previous option; with the list closed, open it at the last option", "Home": "Move to the first option of an open list", "End": "Move to the last option of an open list", "Enter": "Pick the active option and close the list", "Escape": "Close the list; with the list closed, clear the field" }, "interaction": "interactive", "event": [{ "trigger": "keyboard", "target": 'input[role="combobox"]', "key": "Tab", "effect": { "kind": "focus" } }, { "trigger": "keyboard", "target": 'input[role="combobox"]', "key": "x", "effect": { "kind": "value", "value": "Canadax" } }, { "trigger": "keyboard", "target": 'input[role="combobox"]', "key": "ArrowDown", "effect": { "kind": "active-option", "value": "Australia" } }, { "trigger": "keyboard", "target": 'input[role="combobox"]', "key": "ArrowUp", "effect": { "kind": "active-option", "value": "United States" } }, { "trigger": "keyboard", "target": 'input[role="combobox"]', "keys": ["ArrowUp"], "key": "Home", "effect": { "kind": "active-option", "value": "Australia" } }, { "trigger": "keyboard", "target": 'input[role="combobox"]', "keys": ["ArrowDown"], "key": "End", "effect": { "kind": "active-option", "value": "United States" } }, { "trigger": "keyboard", "target": 'input[role="combobox"]', "keys": ["ArrowDown", "ArrowDown", "ArrowDown"], "key": "Enter", "effect": { "kind": "event", "value": "fr" } }, { "trigger": "keyboard", "target": 'input[role="combobox"]', "key": "Escape", "effect": { "kind": "event", "value": "" } }] },
15505
15755
  CycleProgressCard: { "role": "none", "name": { "strategy": "heading", "target": "h1,h2,h3,h4,h5,h6" }, "keyboard": {}, "interaction": "none", "interactionReason": "CycleProgressCard presents content and owns no focusable control or action; authored child actions remain the consumer's responsibility.", "event": [] },
15506
15756
  DatePicker: { "role": "none", "name": { "strategy": "label", "target": 'input[type="date"]' }, "keyboard": { "Tab": "Move focus to the named native control" }, "interaction": "interactive", "event": [{ "trigger": "keyboard", "target": 'input[type="date"]', "key": "Tab", "effect": { "kind": "focus" } }] },
15507
15757
  DetailHeader: { "role": "none", "name": { "strategy": "heading", "target": "h1,h2,h3,h4,h5,h6" }, "keyboard": {}, "interaction": "none", "interactionReason": "DetailHeader presents content and owns no focusable control or action; authored child actions remain the consumer's responsibility.", "event": [] },
@@ -15533,6 +15783,9 @@ var componentBehaviors = {
15533
15783
  RoleAssignmentForm: { "role": "textbox", "name": { "strategy": "label", "target": 'input[name="assignee"]' }, "keyboard": { "Tab": "Move focus to the named native control", "x": "Edit the named control" }, "interaction": "interactive", "event": [{ "trigger": "keyboard", "target": 'input[name="assignee"]', "key": "Tab", "effect": { "kind": "focus" } }, { "trigger": "keyboard", "target": 'input[name="assignee"]', "effect": { "kind": "value", "value": "ada@example.testx" }, "key": "x" }] },
15534
15784
  RoleBadgeList: { "role": "none", "name": { "strategy": "none", "target": ":root" }, "keyboard": {}, "interaction": "none", "interactionReason": "RoleBadgeList presents content and owns no focusable control or action; authored child actions remain the consumer's responsibility.", "event": [] },
15535
15785
  SearchInput: { "role": "searchbox", "name": { "strategy": "label", "target": "input" }, "keyboard": { "Tab": "Move focus to the named native control", "Escape": "Clear the current search" }, "interaction": "interactive", "event": [{ "trigger": "keyboard", "target": "input", "key": "Escape", "effect": { "kind": "event", "value": "" } }, { "trigger": "keyboard", "target": "input", "key": "Tab", "effect": { "kind": "focus" } }, { "trigger": "pointer", "target": 'button[aria-label="Clear search"]', "action": "click", "effect": { "kind": "event", "value": "" } }] },
15786
+ // s223-m02 (#2527 ruling 10): the focus target is the checked radio, as Tabs names its tab; the radiogroup and its name
15787
+ // are asserted in each framework's scenario spec. The browser owns the keys, so each is a native radio-group move.
15788
+ SegmentedControl: { "role": "radio", "name": { "strategy": "label", "target": 'input[type="radio"]:checked' }, "keyboard": { "Tab": "Move focus to the checked option", "ArrowRight": "Check and focus the next option", "ArrowDown": "Check and focus the next option", "ArrowLeft": "Check and focus the previous option", "ArrowUp": "Check and focus the previous option" }, "interaction": "interactive", "event": [{ "trigger": "keyboard", "target": 'input[type="radio"]:checked', "key": "Tab", "effect": { "kind": "focus" } }, { "trigger": "keyboard", "target": 'input[type="radio"]:checked', "key": "ArrowRight", "effect": { "kind": "event", "value": "yearly" } }, { "trigger": "keyboard", "target": 'input[type="radio"]:checked', "key": "ArrowDown", "effect": { "kind": "event", "value": "yearly" } }, { "trigger": "keyboard", "target": 'input[type="radio"]:checked', "key": "ArrowLeft", "effect": { "kind": "event", "value": "monthly" } }, { "trigger": "keyboard", "target": 'input[type="radio"]:checked', "key": "ArrowUp", "effect": { "kind": "event", "value": "monthly" } }, { "trigger": "pointer", "target": 'input[value="yearly"]', "effect": { "kind": "event", "value": "yearly" }, "action": "click" }] },
15536
15789
  Select: { "role": "combobox", "name": { "strategy": "label", "target": "select" }, "keyboard": { "Tab": "Move focus to the named native control" }, "interaction": "interactive", "event": [{ "trigger": "keyboard", "target": "select", "key": "Tab", "effect": { "kind": "focus" } }, { "trigger": "pointer", "target": "select", "effect": { "kind": "event", "value": "basic" }, "action": "select", "value": "basic" }] },
15537
15790
  Stack: { "role": "none", "name": { "strategy": "none", "target": ":root" }, "keyboard": {}, "interaction": "none", "interactionReason": "Stack presents content and owns no focusable control or action; authored child actions remain the consumer's responsibility.", "event": [] },
15538
15791
  StatusBadge: { "role": "none", "name": { "strategy": "none", "target": ":root" }, "keyboard": {}, "interaction": "none", "interactionReason": "StatusBadge presents content and owns no focusable control or action; authored child actions remain the consumer's responsibility.", "event": [] },
@@ -15564,7 +15817,7 @@ var authoredContracts = {
15564
15817
  states: ["summary", "content"],
15565
15818
  tokenRoles: ["panel.background", "panel.border", "panel.title", "panel.subtitle"],
15566
15819
  accessibility: ["A real h3 heading names the panel section", "Subtitle and summary text remain visible beside the heading", "The panel is noninteractive"],
15567
- compatibility: "Mirrors renderAddressCollectionPanel over renderPanelSection with data-panel-type=address: title aliases title/label/heading/name (default Addresses), subtitle aliases subtitle/description/metadata, and summary/text/body/emptyMessage fill the content area only without authored children. The saved-schema directives roleField, defaultRoleField and roleParameter are consumed by codegen and left unbound, and the generic field (the addresses collection) is consumed without a binding: the HTML renderer reads no address data, so the panel presents its heading, subtitle, summary and authored children only."
15820
+ compatibility: "Mirrors renderAddressCollectionPanel over renderPanelSection with data-panel-type=address: title aliases title/label/heading/name (default Addresses), subtitle aliases subtitle/description/metadata, and summary/text/body/emptyMessage fill the content area only without authored children. The saved-schema directives roleField, defaultRoleField and roleParameter are consumed by codegen and left unbound. The generic field (the addresses collection) lowers to summary, the record's addresses one line each (addressCollectionSummary; a generated workflow's store prints the same line), in every renderer and on a single screen as in a workflow."
15568
15821
  },
15569
15822
  AddressEditor: {
15570
15823
  id: "AddressEditor",
@@ -15599,17 +15852,17 @@ var authoredContracts = {
15599
15852
  accessibility: ["A log region named by its title, which is also a real h3 heading", "Events are an ordered list with machine-readable timestamps", "An empty timeline is named No events"],
15600
15853
  compatibility: "Mirrors renderAddressValidationTimeline over renderTimelineContainer with data-timeline-type=address-validation and role=log: title aliases title/label/heading/name (default Address Validation Timeline); the first array among events/validations/history supplies the events, each rendered as label, time and detail exactly as normalizeTimelineItems reads them (records use label/title/event/status/state/text/name, timestamp/datetime/time/at/createdAt/updatedAt and detail/description/reason/message/from/to; scalars render as text); no events renders the named empty item; authored children replace the list. The generic field (the addresses collection) lowers to events."
15601
15854
  },
15602
- ArchiveEvent: { "id": "ArchiveEvent", "version": "1.1.0", "props": ["title", "archivedAt", "restoredAt", "archivedBy", "reason", "showActor", "showReason"], "slots": [], "events": [], "states": ["empty", "populated"], "tokenRoles": ["surface.panel", "text.body"], "accessibility": ["Visible text exposes values without relying on color", "Named semantic container or noninteractive span"], "compatibility": "Archive and restoration instants remain distinct and ordered as declared; valid dates render stable UTC time, missing dates remain disclosed. Actor and reason are visible when supplied. metadataField and restorationMetadataField are consumed unbound, matching the retained renderer; metadata inspection is not claimed." },
15855
+ ArchiveEvent: { "id": "ArchiveEvent", "version": "1.1.0", "props": ["title", "archivedAt", "restoredAt", "archivedBy", "reason", "showActor", "showReason"], "slots": [], "events": [], "states": ["empty", "populated"], "tokenRoles": ["surface.panel", "text.body"], "accessibility": ["Visible text exposes values without relying on color", "Named semantic container or noninteractive span"], "compatibility": "Archive and restoration instants remain distinct and ordered as declared; valid dates render stable UTC time, missing dates remain disclosed. Actor and reason are visible when supplied; with no archive or restore recorded the card renders nothing (s223-m01). metadataField and restorationMetadataField are consumed unbound, matching the retained renderer; metadata inspection is not claimed." },
15603
15856
  ArchivePill: {
15604
15857
  id: "ArchivePill",
15605
15858
  version: COMPONENT_CONTRACT_VERSION,
15606
- props: ["label", "text", "status", "state", "value", "variant", "tone", "emphasis", "isArchived"],
15859
+ props: ["label", "text", "status", "state", "value", "variant", "tone", "emphasis", "isArchived", "hideWhenFalse"],
15607
15860
  slots: ["default"],
15608
15861
  events: [],
15609
15862
  states: ["subtle", "solid"],
15610
15863
  tokenRoles: ["badge.background", "badge.text"],
15611
15864
  accessibility: ["false remains visible", "archive is the badge variant"],
15612
- compatibility: "Mirrors renderArchivePill over renderBadgePrimitive: label/text/status/state/isArchived/value label precedence, status/state/isArchived/value status precedence, Archive fallback and archive variant. Boolean flags read Not archived / Archived while preserving their recorded status; absent flags remain absent and authored labels or children win. field binds isArchived. archivedAtField is consumed unbound because the HTML pill has no date term. Noninteractive; no archive or restore action."
15865
+ compatibility: 'Mirrors renderArchivePill over renderBadgePrimitive: label/text/status/state/isArchived/value label precedence, status/state/isArchived/value status precedence, Archive fallback and archive variant. Boolean flags read Not archived / Archived while preserving their recorded status; absent flags remain absent and authored labels or children win. field binds isArchived. With hideWhenFalse a false flag renders nothing (s223-m01: a card shows "Archived", never the default "Not archived"); a true flag still reads Archived. archivedAtField is consumed unbound because the HTML pill has no date term. Noninteractive; no archive or restore action.'
15613
15866
  },
15614
15867
  ArchiveSummary: {
15615
15868
  id: "ArchiveSummary",
@@ -15747,15 +16000,15 @@ var authoredContracts = {
15747
16000
  CancellationBadge: {
15748
16001
  id: "CancellationBadge",
15749
16002
  version: COMPONENT_CONTRACT_VERSION,
15750
- props: ["label", "text", "status", "state", "value", "variant", "tone", "emphasis", "cancelAtPeriodEnd", "isCancelled"],
16003
+ props: ["label", "text", "status", "state", "value", "variant", "tone", "emphasis", "cancelAtPeriodEnd", "isCancelled", "hideWhenFalse"],
15751
16004
  slots: ["default"],
15752
16005
  events: [],
15753
16006
  states: ["subtle", "solid"],
15754
16007
  tokenRoles: ["badge.background", "badge.text"],
15755
16008
  accessibility: ["false remains visible", "cancellation is the badge variant"],
15756
- compatibility: "Mirrors renderCancellationBadge over renderBadgePrimitive: label/text/status/state/cancelAtPeriodEnd/value label precedence; status/state/cancelAtPeriodEnd/isCancelled/value status precedence; Cancellation fallback and cancellation variant. Boolean flags read No cancellation scheduled / Cancellation scheduled while preserving their recorded status; absent flags remain absent. field binds cancelAtPeriodEnd. Authored labels or children win. Noninteractive; no cancellation action."
16009
+ compatibility: 'Mirrors renderCancellationBadge over renderBadgePrimitive: label/text/status/state/cancelAtPeriodEnd/value label precedence; status/state/cancelAtPeriodEnd/isCancelled/value status precedence; Cancellation fallback and cancellation variant. Boolean flags read No cancellation scheduled / Cancellation scheduled while preserving their recorded status; absent flags remain absent. field binds cancelAtPeriodEnd. With hideWhenFalse a false flag renders nothing (s223-m01: a card shows "Cancellation scheduled", never the default "No cancellation scheduled"); a true flag still reads Cancellation scheduled. Authored labels or children win. Noninteractive; no cancellation action.'
15757
16010
  },
15758
- CancellationEvent: { "id": "CancellationEvent", "version": "1.1.0", "props": ["title", "timestamp", "reason", "code", "showReason"], "slots": [], "events": [], "states": ["empty", "populated"], "tokenRoles": ["surface.panel", "text.body"], "accessibility": ["Visible text exposes values without relying on color", "Named semantic container or noninteractive span"], "compatibility": "Cancellation timestamp, reason and code are visible without initiating cancellation; an absent request remains an explicit empty state." },
16011
+ CancellationEvent: { "id": "CancellationEvent", "version": "1.1.0", "props": ["title", "timestamp", "reason", "code", "showReason"], "slots": [], "events": [], "states": ["empty", "populated"], "tokenRoles": ["surface.panel", "text.body"], "accessibility": ["Visible text exposes values without relying on color", "Named semantic container or noninteractive span"], "compatibility": "Cancellation timestamp, reason and code are visible without initiating cancellation; with no request recorded the card renders nothing (s223-m01: an empty card is not content)." },
15759
16012
  CancellationForm: {
15760
16013
  id: "CancellationForm",
15761
16014
  version: COMPONENT_CONTRACT_VERSION,
@@ -15869,6 +16122,25 @@ var authoredContracts = {
15869
16122
  accessibility: ["Inherits Badge inline noninteractive status label semantics", "A visible text label always accompanies the decorative color marker", "Color is never the sole status signal"],
15870
16123
  compatibility: "Mirrors renderColorizedBadge over renderBadgePrimitive label/status/color aliases and default variant colorized; Badge tone and emphasis retain their shared behavior."
15871
16124
  },
16125
+ // s223-m02 (#2527 ruling 11): pick one value from a list by typing to filter it, the WAI-ARIA combobox pattern with a
16126
+ // listbox popup. One markup in React, Vue and HTML; HTML's inline script gives it the same behaviour.
16127
+ Combobox: {
16128
+ id: "Combobox",
16129
+ version: COMPONENT_CONTRACT_VERSION,
16130
+ requiredProps: ["id", "label"],
16131
+ props: ["id", "label", "options", "value", "defaultValue", "placeholder", "name", "required", "disabled", "help", "validation", "size"],
16132
+ slots: ["label", "help", "validation"],
16133
+ events: ["change", "update"],
16134
+ states: ["closed", "open", "no-matches", "selected", "disabled", "invalid"],
16135
+ tokenRoles: ["input.background", "input.border", "input.text", "input.placeholder", "input.focus", "combobox.popup", "combobox.shadow", "combobox.option", "combobox.optionActive", "combobox.check", "field.message"],
16136
+ accessibility: [
16137
+ "An input with role combobox controls a listbox popup and reports aria-expanded, aria-autocomplete list and, while an option is active, aria-activedescendant; focus stays in the input",
16138
+ "The visible label names the combobox and its listbox; help and error text describe the input",
16139
+ "The chosen option reports aria-selected and shows a check mark; a disabled option reports aria-disabled and is skipped",
16140
+ "Down opens the list and moves, Up moves, Home and End go to the ends, Enter picks the active option, Escape closes the list and then clears the field, and Tab closes the list without picking"
16141
+ ],
16142
+ compatibility: 'Typing filters the options to those whose label contains the typed text, ignoring case, and opens the list; when none matches the popup says No matches, which is not an option. value (controlled) or defaultValue (uncontrolled) names the chosen option, and the input shows its label. Picking an option (Enter on the active one, or a click) emits change and update with its value and closes the list; Escape with the list closed empties the input and, when an option was chosen, emits them with an empty value. An outside click or Tab closes the list without picking, and leaving the field restores the chosen label. size is the control height: xs 24, sm 28, md 32 (default) or lg 40, as Input, Select and Button. name submits the chosen value through a hidden input. The HTML renderer writes the same markup with the list closed and appends an inline script (data-oods-runtime="combobox") that gives it the same behaviour; without the script the input still shows the chosen label. One value only: no multiple selection, async loading, created values, grouped options or virtualization.'
16143
+ },
15872
16144
  CommunicationDetailPanel: { "id": "CommunicationDetailPanel", "version": "1.1.0", "props": ["title", "channels", "templates", "policies", "conversations"], "slots": [], "events": [], "states": ["empty", "populated"], "tokenRoles": ["surface.panel", "text.body"], "accessibility": ["Visible text exposes values without relying on color", "Named semantic container or noninteractive span"], "compatibility": "A named read-only section renders declared channel, template, delivery policy and conversation entries. A polite status announces the conversation count; it performs no delivery or network operation." },
15873
16145
  CycleProgressCard: {
15874
16146
  id: "CycleProgressCard",
@@ -15914,7 +16186,7 @@ var authoredContracts = {
15914
16186
  states: ["open", "closed"],
15915
16187
  tokenRoles: ["dialog.background", "dialog.border", "dialog.shadow", "dialog.backdrop", "dialog.title", "dialog.description"],
15916
16188
  accessibility: ["A native dialog element named by its h2 title (aria-labelledby) and described by its description (aria-describedby)", "The close control is a ghost icon button named by dismissLabel (default Close)", "Escape and the close control emit close"],
15917
- compatibility: "The consumer owns open: the close control, Escape and a browser close request emit close, and the dialog stays open until open becomes false. modal (default true) opens it in the browser with showModal(), over a backdrop with the page behind it inert; modal false shows it in place, which a gallery or a static page uses. Server-rendered and static HTML carry the open attribute while open. size sets the largest inline size: sm 400px, md 512px or lg 640px. The default slot is the body; the actions slot (or the actions prop) is the right-aligned footer, and the HTML renderer draws a string or { label, intent } list there as buttons."
16189
+ compatibility: "The consumer owns open: the close control, Escape and a browser close request emit close, and the dialog stays open until open becomes false. modal (default true) opens it in the browser with showModal(), over a backdrop with the page behind it inert and not scrolling (the page's own overflow and padding come back exactly when it closes, by any route, or unmounts), and a click on the backdrop emits close; modal false shows it in place, which a gallery or a static page uses. Server-rendered and static HTML carry the open attribute while open, and on a static page an inline runtime script makes the close control close it. size sets the largest inline size: sm 400px, md 512px or lg 640px. The default slot is the body; the actions slot (or the actions prop) is the right-aligned footer, and the HTML renderer draws a string or { label, intent } list there as buttons."
15918
16190
  },
15919
16191
  FilterPanel: {
15920
16192
  id: "FilterPanel",
@@ -16044,13 +16316,13 @@ var authoredContracts = {
16044
16316
  OwnershipMeta: {
16045
16317
  id: "OwnershipMeta",
16046
16318
  version: COMPONENT_CONTRACT_VERSION,
16047
- props: ["title", "label", "heading", "name", "ownerType", "owner_type", "role", "ownershipRole"],
16319
+ props: ["title", "label", "heading", "name", "ownerType", "owner_type", "role", "ownershipRole", "ownerLabel"],
16048
16320
  slots: ["default"],
16049
16321
  events: [],
16050
16322
  states: ["populated", "empty"],
16051
16323
  tokenRoles: ["meta.text", "meta.label"],
16052
16324
  accessibility: ["metadata has inline term labels", "role is visible text not an ARIA role"],
16053
- compatibility: "Mirrors renderOwnershipMeta over renderMetaInline: title/label/heading/name (default Ownership), Owner Type ownerType/owner_type, Role role/ownershipRole. Each value is an inline span with a strong term and separator; children replace the entire body including its title. ownerTypeField and roleField lower to their consumed keys. role is displayed data, never an ARIA role. Noninteractive."
16325
+ compatibility: 'Mirrors renderOwnershipMeta over renderMetaInline: title/label/heading/name (default Ownership), Owner Type ownerType/owner_type, Role role/ownershipRole. Each value is an inline span with a strong term and separator; children replace the entire body including its title. ownerTypeField and roleField lower to their consumed keys. s223-m01: given ownerLabel (ownerIdField binds the display label of the owner reference) the body is one phrase, "Owned by <label> \xB7 <type> \xB7 <role>", or "<Type>-owned" when the reference has no name. role is displayed data, never an ARIA role. Noninteractive.'
16054
16326
  },
16055
16327
  OwnershipSummary: {
16056
16328
  id: "OwnershipSummary",
@@ -16273,6 +16545,19 @@ var authoredContracts = {
16273
16545
  accessibility: ["Native search input semantics", "Clear control has an accessible label"],
16274
16546
  compatibility: "Debounce and minimum-query settings preserve value updates across both targets."
16275
16547
  },
16548
+ // s223-m02 (#2527 ruling 10): one choice from two to five options, shown as joined segments.
16549
+ SegmentedControl: {
16550
+ id: "SegmentedControl",
16551
+ version: COMPONENT_CONTRACT_VERSION,
16552
+ requiredProps: ["id", "label"],
16553
+ props: ["id", "label", "options", "value", "defaultValue", "name", "size", "disabled"],
16554
+ slots: ["label"],
16555
+ events: ["change", "update"],
16556
+ states: ["selected", "unselected", "disabled"],
16557
+ tokenRoles: ["segmented.track", "segmented.selected", "segmented.ring", "segmented.text", "segmented.focus"],
16558
+ accessibility: ["Native radio inputs in a radiogroup named by its visible label through aria-labelledby", "Each option is a radio inside its own label, so the option text names it", "The browser gives the radio-group keyboard: the arrows move and check, and Tab enters at the checked option"],
16559
+ compatibility: "One choice from two to five options, each { value, label, disabled }, shown as joined segments in sizes xs, sm, md and lg: 24, 28, 32 and 40px, the button, input and select heights at each size. value (controlled) or defaultValue (uncontrolled) checks one option; with neither, none is checked and Tab enters at the first. name groups the radios and defaults to the id; disabled disables every option. Each change emits change and update with the chosen value. React, Vue and the HTML renderer write one markup, and the HTML needs no script: the native radios carry the keyboard. Icon-only segments and more than one selection are not part of it."
16560
+ },
16276
16561
  Select: {
16277
16562
  id: "Select",
16278
16563
  version: COMPONENT_CONTRACT_VERSION_1_1,
@@ -16298,7 +16583,7 @@ var authoredContracts = {
16298
16583
  accessibility: ["Does not alter child semantics"],
16299
16584
  compatibility: "Maps saved-schema stack and inline modes to one flex primitive; patternComponent and fields are executed composition directives. Trait recipe directives authored on pattern-group Stacks are consumed by codegen: channelsField, templatesField, policiesField, conversationsField, labelField and showActor are left unbound (a layout container reads no data and the lowered StatusTimeline never governed them), while historyField and showReason travel with the lowering to the StatusTimeline whose contract governs them. Two more authoring leftovers are consumed unbound: the form composer leaves as on a Stack when it expands a heading title slot into several components, and a pattern-group Stack restates its first fields entry as a generic field; a layout container renders neither."
16300
16585
  },
16301
- StateTransitionEvent: { "id": "StateTransitionEvent", "version": "1.1.0", "props": ["title", "history", "status", "showActor", "showReason"], "slots": [], "events": [], "states": ["empty", "populated"], "tokenRoles": ["surface.panel", "text.body"], "accessibility": ["Visible text exposes values without relying on color", "Named semantic container or noninteractive span"], "compatibility": "Declared history order, from/to states, actor and reason remain visible; showActor/showReason suppress their respective details. No history is invented." },
16586
+ StateTransitionEvent: { "id": "StateTransitionEvent", "version": "1.1.0", "props": ["title", "history", "status", "showActor", "showReason"], "slots": [], "events": [], "states": ["empty", "populated"], "tokenRoles": ["surface.panel", "text.body"], "accessibility": ["Visible text exposes values without relying on color", "Named semantic container or noninteractive span"], "compatibility": "Declared history order, from/to states, actor and reason remain visible; showActor/showReason suppress their respective details. No history is invented; with no history the card renders nothing (s223-m01)." },
16302
16587
  StatusBadge: {
16303
16588
  id: "StatusBadge",
16304
16589
  version: COMPONENT_CONTRACT_VERSION,
@@ -16378,7 +16663,7 @@ var authoredContracts = {
16378
16663
  states: ["off", "on", "disabled", "invalid"],
16379
16664
  tokenRoles: ["switch.track", "switch.thumb", "switch.border", "switch.focus", "field.message"],
16380
16665
  accessibility: ["A native button with role switch reports its state in aria-checked", "The visible label names the switch; help and error text describe it", "Space and Enter toggle it"],
16381
- compatibility: "Shares the Checkbox field API for a setting that applies at once: checked (controlled) or defaultChecked (uncontrolled), required, disabled, help and validation, in sizes sm and md. Each toggle emits change and update with the next checked value. The HTML renderer paints the same markup without script, so a static page shows the state and does not toggle."
16666
+ compatibility: `Shares the Checkbox field API for a setting that applies at once: checked (controlled) or defaultChecked (uncontrolled), required, disabled, help and validation, in sizes sm and md. Each toggle emits change and update with the next checked value. The HTML renderer paints the same markup and an inline runtime script turns it over on a static page (aria-checked, from a click, Space or Enter); bound to a form field it also carries the field's value, "true" or "false", in a hidden input the script keeps. Bound to a record field in a generated form, it reads and writes the field's boolean as Checkbox does.`
16382
16667
  },
16383
16668
  Table: {
16384
16669
  id: "Table",
@@ -16630,7 +16915,7 @@ var authoredScenarios = [
16630
16915
  { "id": "VizSizeControls", "oodsComponentId": "VizSizeControls", "props": { "value": { "encodings": { "size": { "field": "size", "scale": "linear" } } } }, "slots": {}, "initialState": { "encodings": { "size": { "field": "size", "scale": "linear" } } }, "renderExpectation": { "name": "change", "trigger": "append x to the first field", "expected": '{"encodings":{"size":{"field":"sizex","scale":"linear"}}}' }, "assertions": ["emitted payload is a typed public input fragment", "untouched sibling bindings are preserved", "labels name native controls"] },
16631
16916
  { "id": "VizSizeSummary", "oodsComponentId": "VizSizeSummary", "props": { "value": { "encodings": { "size": { "field": "size", "scale": "linear" } } } }, "slots": {}, "initialState": { "authored": true }, "renderExpectation": { "name": "render", "trigger": "mount the authored fragment or shared-renderer SVG", "expected": '{"encodings":{"size":{"field":"size","scale":"linear"}}}' }, "assertions": ["authored binding values remain readable", "no interactive chart action is implied"] },
16632
16917
  { "id": "ArchiveEvent", "oodsComponentId": "ArchiveEvent", "props": { "archivedAt": "2026-09-01T12:00:00Z", "restoredAt": "2026-09-02T12:00:00Z", "archivedBy": "operator-1", "reason": "Duplicate record" }, "slots": {}, "initialState": {}, "renderExpectation": { "name": "render", "trigger": "mount and declared input triggers", "expected": "Archive and restoration instants remain distinct and ordered as declared; valid dates render stable UTC time, missing dates remain disclosed. Actor and reason are visible when supplied." }, "assertions": ["Visible text exposes values without relying on color", "Named semantic container or noninteractive span"] },
16633
- { "id": "CancellationEvent", "oodsComponentId": "CancellationEvent", "props": { "timestamp": "2026-09-01T12:00:00Z", "reason": "Customer request", "code": "customer_request" }, "slots": {}, "initialState": {}, "renderExpectation": { "name": "render", "trigger": "mount and declared input triggers", "expected": "Cancellation timestamp, reason and code are visible without initiating cancellation; an absent request remains an explicit empty state." }, "assertions": ["Visible text exposes values without relying on color", "Named semantic container or noninteractive span"] },
16918
+ { "id": "CancellationEvent", "oodsComponentId": "CancellationEvent", "props": { "timestamp": "2026-09-01T12:00:00Z", "reason": "Customer request", "code": "customer_request" }, "slots": {}, "initialState": {}, "renderExpectation": { "name": "render", "trigger": "mount and declared input triggers", "expected": "Cancellation timestamp, reason and code are visible without initiating cancellation; with no request recorded the card renders nothing." }, "assertions": ["Visible text exposes values without relying on color", "Named semantic container or noninteractive span"] },
16634
16919
  { "id": "StateTransitionEvent", "oodsComponentId": "StateTransitionEvent", "props": { "history": [{ "from_state": "draft", "to_state": "active", "transitioned_at": "2026-09-01T12:00:00Z", "actor_id": "operator-1", "reason": "Approved" }] }, "slots": {}, "initialState": {}, "renderExpectation": { "name": "render", "trigger": "mount and declared input triggers", "expected": "Declared history order, from/to states, actor and reason remain visible; showActor/showReason suppress their respective details. No history is invented." }, "assertions": ["Visible text exposes values without relying on color", "Named semantic container or noninteractive span"] },
16635
16920
  { "id": "ColorStatePicker", "oodsComponentId": "ColorStatePicker", "props": { "colorStates": ["neutral", "success"], "value": "neutral" }, "slots": {}, "initialState": {}, "renderExpectation": { "name": "render", "trigger": "mount and declared input triggers", "expected": "A labelled Select inside a fieldset edits only declared semantic color states and emits one string change; prop changes resynchronise local selection." }, "assertions": ["Visible text explains the declared trait values", "Every native control has a visible label"] },
16636
16921
  { "id": "StatusColorLegend", "oodsComponentId": "StatusColorLegend", "props": { "colorStates": ["neutral", "success"], "value": "success", "showTokenReferences": true }, "slots": {}, "initialState": {}, "renderExpectation": { "name": "render", "trigger": "mount and declared input triggers", "expected": "A named section pairs semantic color swatches with visible state names, the current state and optional token references. Meaning is never color alone." }, "assertions": ["Visible text exposes values without relying on color", "Named semantic container or noninteractive span"] },
@@ -16645,7 +16930,7 @@ var authoredScenarios = [
16645
16930
  { id: "address-editor-fields-and-change", oodsComponentId: "AddressEditor", props: { title: "Shipping address", street: "1 Main St", city: "Springfield", region: "IL", postalCode: "62701" }, slots: {}, initialState: { street: "1 Main St" }, renderExpectation: { name: "change", trigger: "type into the City input", expected: "change emitted with the current street/city/region/postalCode record" }, assertions: ["title is a real h2 heading", "four labelled inputs are prefilled", "change carries the whole address record", "submitting is a no-op"] },
16646
16931
  { id: "address-summary-badge-role", oodsComponentId: "AddressSummaryBadge", props: { label: "Billing address", role: "billing" }, slots: {}, initialState: { status: "billing" }, renderExpectation: { name: "render", trigger: "mount", expected: "visible Billing address label with data-badge-status billing and the address variant" }, assertions: ["label is visible text", "data-badge-status is billing", "data-badge-variant is address", "badge is noninteractive"] },
16647
16932
  { id: "address-validation-timeline-events", oodsComponentId: "AddressValidationTimeline", props: { title: "Address checks", validations: [{ label: "Postal code verified", timestamp: "2026-09-05T12:00:00Z", detail: "Matched carrier database" }, "Geocoded"] }, slots: {}, initialState: { events: 2 }, renderExpectation: { name: "render", trigger: "mount", expected: "a log region titled Address checks with two ordered events, the first timestamped and detailed" }, assertions: ["region has role log and an h2 title", "events are ordered list items", "the timestamp is a time element", "scalar entries render as text"] },
16648
- { id: "archive-pill-false", oodsComponentId: "ArchivePill", props: { "isArchived": false }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "Not archived remains visible; machine status remains false; archive is the badge variant" }, assertions: ["Not archived remains visible; machine status remains false", "archive is the badge variant"] },
16933
+ { id: "archive-pill-false", oodsComponentId: "ArchivePill", props: { "isArchived": false }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "Not archived remains visible; machine status remains false; archive is the badge variant; with hideWhenFalse a false flag renders nothing and a true flag reads Archived" }, assertions: ["Not archived remains visible; machine status remains false", "archive is the badge variant", "hideWhenFalse hides only the default"] },
16649
16934
  { id: "archive-summary-false-and-reason", oodsComponentId: "ArchiveSummary", props: { "isArchived": false, "archivedAt": "2026-09-05T12:00:00Z", "reason": "Retention policy" }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "No remains visible in its named term; archive date and reason remain associated terms" }, assertions: ["No remains visible in its named term", "archive date and reason remain associated terms"] },
16650
16935
  { id: "archived-row-presentation", oodsComponentId: "ArchivedRowOverlay", props: { "isArchived": true, "showBadge": true, "separateTab": true, "tabLabel": "Archived", "label": "Team subscription" }, slots: {}, initialState: {}, renderExpectation: { name: "render", trigger: "mount", expected: "Archived row stays accessible and its badge and tab label agree" }, assertions: ["Archived row stays accessible and its badge and tab label agree"] },
16651
16936
  { id: "audit-event-type-and-timestamp", oodsComponentId: "AuditEvent", props: { event: "user.updated", timestamp: "2026-09-05T12:00:00Z", detail: "Display name changed" }, slots: {}, initialState: { timestamped: true }, renderExpectation: { name: "render", trigger: "mount", expected: "one audit article with a machine-readable time, the event label and the detail" }, assertions: ["article carries data-event-type audit", "time element has a datetime", "label and detail are visible text"] },
@@ -16665,7 +16950,7 @@ var authoredScenarios = [
16665
16950
  { id: "billing-interval-subscription", oodsComponentId: "BillingIntervalSelector", props: { interval: "monthly", intervals: ["monthly", "yearly"], label: "Billing interval" }, slots: {}, initialState: { interval: "monthly" }, renderExpectation: { name: "change", trigger: "ArrowDown from monthly", expected: "yearly selected and emitted" }, assertions: ["only the resolved object intervals are selectable", "a native select supports keyboard selection", "invalid interval is announced"] },
16666
16951
  { id: "billing-summary-minor-units", oodsComponentId: "BillingSummaryBadge", props: { amount: 1999, currency: "usd", minorUnits: 100, interval: "monthly" }, slots: {}, initialState: {}, renderExpectation: { name: "render", trigger: "mount", expected: "$19.99 \xB7 monthly" }, assertions: ["integer minor units format as a currency amount", "one visible phrase includes interval"] },
16667
16952
  { id: "button-activate", oodsComponentId: "Button", props: { content: "Save changes", intent: "neutral", size: "md" }, slots: { default: "Save changes" }, initialState: { disabled: false }, renderExpectation: { name: "activate", trigger: "pointer click or Enter", expected: "activation handler called once" }, assertions: ["native type defaults to button", "focus is visible"] },
16668
- { id: "cancellation-badge-false", oodsComponentId: "CancellationBadge", props: { "cancelAtPeriodEnd": false }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "No cancellation scheduled remains visible; machine status remains false; cancellation is the badge variant" }, assertions: ["No cancellation scheduled remains visible; machine status remains false", "cancellation is the badge variant"] },
16953
+ { id: "cancellation-badge-false", oodsComponentId: "CancellationBadge", props: { "cancelAtPeriodEnd": false }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "No cancellation scheduled remains visible; machine status remains false; cancellation is the badge variant; with hideWhenFalse a false flag renders nothing and a true flag reads Cancellation scheduled" }, assertions: ["No cancellation scheduled remains visible; machine status remains false", "cancellation is the badge variant", "hideWhenFalse hides only the default"] },
16669
16954
  { id: "cancellation-form-presentational-controls", oodsComponentId: "CancellationForm", props: { "title": "Cancellation request", "reasonCode": "budget", "reason": "Costs changed" }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "reason and code retain their initial values; native controls are labelled; submit does not cancel or save" }, assertions: ["reason and code retain their initial values", "native controls are labelled", "submit does not cancel or save"] },
16670
16955
  {
16671
16956
  id: "cancellation-summary-boolean",
@@ -16682,6 +16967,8 @@ var authoredScenarios = [
16682
16967
  // s222-m02 (#2502 ruling 11): the two components 0.4.0 adds. The dialog example is shown in place (modal false), as a
16683
16968
  // gallery shows it; modal true is the default.
16684
16969
  { id: "dialog-confirm", oodsComponentId: "Dialog", props: { id: "archive-workspace", open: true, modal: false, title: "Archive workspace", description: "Members lose access until the workspace is restored.", size: "sm" }, slots: { default: "Invoices and subscriptions stay in the archive for 30 days.", actions: ["Cancel", "Archive workspace"] }, initialState: { open: true }, renderExpectation: { name: "close", trigger: "activate the close button or press Escape", expected: "close emitted once; the dialog stays open until open becomes false" }, assertions: ["the dialog is named by its title and described by its description", "the close button is named", "the actions sit in the footer"] },
16970
+ // s223-m02 (#2527 ruling 11): the combobox example; Japan is disabled, so the keyboard skips it and a click cannot pick it.
16971
+ { id: "combobox-filter-and-pick", oodsComponentId: "Combobox", props: { id: "shipping-country", label: "Shipping country", value: "ca", placeholder: "Search countries", help: "Type to filter. We do not ship to Japan yet.", options: [{ value: "au", label: "Australia" }, { value: "ca", label: "Canada" }, { value: "fr", label: "France" }, { value: "de", label: "Germany" }, { value: "jp", label: "Japan", disabled: true }, { value: "mx", label: "Mexico" }, { value: "gb", label: "United Kingdom" }, { value: "us", label: "United States" }] }, slots: {}, initialState: { open: false, value: "ca" }, renderExpectation: { name: "change", trigger: "type to filter, then Down and Enter, or click an option", expected: "the picked value emitted once and the list closed" }, assertions: ["role combobox controls its listbox and reports aria-expanded", "the label names the combobox and the listbox; help describes the input", "typing filters by label and an empty result says No matches", "the chosen option reports aria-selected and shows a check mark"] },
16685
16972
  { id: "switch-controlled", oodsComponentId: "Switch", props: { id: "payment-alerts", label: "Payment alerts", checked: false, help: "Email the account owner when a payment fails" }, slots: {}, initialState: { checked: false }, renderExpectation: { name: "change", trigger: "click the switch or press Space or Enter", expected: "checked=true emitted once" }, assertions: ["role switch reports aria-checked", "the label names the switch", "help describes the switch"] },
16686
16973
  { id: "classification-badge-category", oodsComponentId: "ClassificationBadge", props: { "category": "Electronics", "mode": "strict" }, slots: {}, initialState: { "content": "populated" }, renderExpectation: { "name": "render", "trigger": "mount", "expected": "category is visible; mode is the status metadata; noninteractive badge" }, assertions: ["category is visible", "mode is the status metadata", "noninteractive badge"] },
16687
16974
  { id: "classification-editor-presentational-controls", oodsComponentId: "ClassificationEditor", props: { "title": "Product classification", "category": "Electronics", "tags": ["alpha", "beta"], "mode": "flexible" }, slots: {}, initialState: { "content": "populated" }, renderExpectation: { "name": "render", "trigger": "mount", "expected": "labelled native inputs retain their values; mode selection is flexible; submit does not navigate or save" }, assertions: ["labelled native inputs retain their values", "mode selection is flexible", "submit does not navigate or save"] },
@@ -16702,7 +16989,7 @@ var authoredScenarios = [
16702
16989
  { id: "message-event-timeline-statuses", oodsComponentId: "MessageEventTimeline", props: { heading: "Delivery", statuses: [{ status: "delivered", at: "2026-09-02T09:00:00Z" }] }, slots: {}, initialState: { events: 1 }, renderExpectation: { name: "render", trigger: "mount with statuses only", expected: "statuses supply the events when messages are absent, in the message timeline type" }, assertions: ["region has role log and an h2 title", "status doubles as the event label", "data-timeline-type is message"] },
16703
16990
  { id: "message-status-badge-delivery", oodsComponentId: "MessageStatusBadge", props: { delivery: "delivered" }, slots: {}, initialState: { status: "delivered" }, renderExpectation: { name: "render", trigger: "mount", expected: "delivery doubles as the visible label and the status in the message variant" }, assertions: ["label is visible text", "data-badge-status is delivered", "data-badge-variant is message", "badge is noninteractive"] },
16704
16991
  { id: "owner-badge-principal", oodsComponentId: "OwnerBadge", props: { "owner": "user-7", "ownerType": "person", "status": "active" }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "owner identity is visible; owner is the badge variant" }, assertions: ["owner identity is visible", "owner is the badge variant"] },
16705
- { id: "ownership-meta-inline-terms", oodsComponentId: "OwnershipMeta", props: { "ownerType": "organization", "role": "custodian" }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "metadata has inline term labels; role is visible text not an ARIA role" }, assertions: ["metadata has inline term labels", "role is visible text not an ARIA role"] },
16992
+ { id: "ownership-meta-inline-terms", oodsComponentId: "OwnershipMeta", props: { "ownerType": "organization", "role": "custodian" }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "metadata has inline term labels; role is visible text not an ARIA role; given ownerLabel one phrase names the owner" }, assertions: ["metadata has inline term labels", "role is visible text not an ARIA role", "ownerLabel reads as one phrase"] },
16706
16993
  { id: "ownership-summary-terms", oodsComponentId: "OwnershipSummary", props: { "ownerId": "user-7", "ownerType": "person", "role": "administrator" }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "a real h2 names the description list; owner label or honest unavailability, type and role remain associated terms" }, assertions: ["a real h2 names the description list", "owner label or honest unavailability, type and role remain associated terms"] },
16707
16994
  {
16708
16995
  id: "pagination-bar-navigation",
@@ -16750,6 +17037,9 @@ var authoredScenarios = [
16750
17037
  renderExpectation: { name: "clear", trigger: "activate clear control", expected: "empty value emitted once" },
16751
17038
  assertions: ["input has search semantics", "clear control is named"]
16752
17039
  },
17040
+ // s223-m02 (#2527 ruling 10): the middle option is checked, so Tab landing on it shows the group's one tab stop is the
17041
+ // checked option, and both arrow directions have a neighbour.
17042
+ { id: "segmented-control-billing-period", oodsComponentId: "SegmentedControl", props: { id: "billing-period", label: "Billing period", value: "quarterly", options: [{ value: "monthly", label: "Monthly" }, { value: "quarterly", label: "Quarterly" }, { value: "yearly", label: "Yearly" }] }, slots: {}, initialState: { value: "quarterly" }, renderExpectation: { name: "change", trigger: "ArrowRight or ArrowLeft from Quarterly, or click Yearly", expected: "the neighbouring value emitted once; the consumer owns value" }, assertions: ["the radiogroup is named by its visible label", "each option is a native radio named by its own label", "the checked option is the value and is the one tab stop"] },
16753
17043
  { id: "select-controlled", oodsComponentId: "Select", props: { id: "plan", label: "Plan", value: "pro", options: [{ value: "basic", label: "Basic" }, { value: "pro", label: "Pro" }] }, slots: {}, initialState: { value: "pro" }, renderExpectation: { name: "change", trigger: "choose Basic", expected: "basic emitted once" }, assertions: ["label targets select", "selected option is visible"] },
16754
17044
  { id: "stack-wrapped-row", oodsComponentId: "Stack", props: { direction: "row", gap: "sm", align: "center", wrap: true }, slots: { default: ["Primary", "Secondary"] }, initialState: { direction: "row", wrap: true }, renderExpectation: { name: "render", trigger: "resize to phone width", expected: "children wrap in DOM order" }, assertions: ["two children remain visible", "gap token is used"] },
16755
17045
  {
@@ -16880,7 +17170,8 @@ var STATUS_ICON_SHAPES = Object.freeze({
16880
17170
  undo: [path("M3 8a5 5 0 1 0 1.5-3.5"), path("M3 2.5v3h3")],
16881
17171
  lock: [{ tag: "rect", attrs: { x: "3.5", y: "7", width: "9", height: "6.5", rx: "1.5" } }, path("M5.5 7V5a2.5 2.5 0 0 1 5 0v2")],
16882
17172
  unlock: [{ tag: "rect", attrs: { x: "3.5", y: "7", width: "9", height: "6.5", rx: "1.5" } }, path("M5.5 7V5a2.5 2.5 0 0 1 4.8-1")],
16883
- dot: [circle("8", "8", "2.5", true)]
17173
+ dot: [circle("8", "8", "2.5", true)],
17174
+ "chevron-down": [path("M4 6l4 4 4-4")]
16884
17175
  });
16885
17176
  var STATUS_ICON_SVG_ATTRS = Object.freeze({
16886
17177
  width: "1em",
@@ -17381,10 +17672,19 @@ function summaryValue(value) {
17381
17672
  function chronologicalEvents(events) {
17382
17673
  return events.filter((event) => Number.isFinite(Date.parse(event.at))).map((event, index) => ({ event, index })).sort((a, b) => Date.parse(a.event.at) - Date.parse(b.event.at) || a.index - b.index).map(({ event }) => event);
17383
17674
  }
17384
- function formatReadOnlyValue(value, type, code = false) {
17675
+ function formatDeclaredNumber(value, format) {
17676
+ const number = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : NaN;
17677
+ if (!Number.isFinite(number)) return void 0;
17678
+ return format === "percent" ? new Intl.NumberFormat("en-US", { style: "percent", maximumFractionDigits: 2 }).format(number / 100) : new Intl.NumberFormat("en-US", { maximumFractionDigits: 2 }).format(number);
17679
+ }
17680
+ function formatReadOnlyValue(value, type, code = false, format) {
17385
17681
  if (value == null || value === "") return "Not recorded";
17386
17682
  if (type === "date" || type === "datetime") return formatDateTime(value) || "Invalid date";
17387
17683
  if (typeof value === "boolean") return value ? "Yes" : "No";
17684
+ if (format && !Array.isArray(value)) {
17685
+ const formatted = formatDeclaredNumber(value, format);
17686
+ if (formatted !== void 0) return formatted;
17687
+ }
17388
17688
  if (Array.isArray(value)) {
17389
17689
  if (value.some((item) => item !== null && typeof item === "object")) return `${value.length} ${value.length === 1 ? "record" : "records"}`;
17390
17690
  return value.map((item) => summaryValue(item) ?? "").join(", ") || "None recorded";
@@ -17421,12 +17721,28 @@ function recordCollectionEvents(record2, options = {}) {
17421
17721
  }
17422
17722
  return chronologicalEvents(events);
17423
17723
  }
17724
+ function addressCollectionSummary(entries) {
17725
+ const asRecord = (value) => value && typeof value === "object" ? value : {};
17726
+ return (Array.isArray(entries) ? entries : []).map((entry) => {
17727
+ const address = asRecord(asRecord(entry).address);
17728
+ const street = Array.isArray(address.addressLines) ? address.addressLines.map(String).join(", ") : "";
17729
+ return [asRecord(entry).role, street, String(address.locality ?? ""), String(address.administrativeArea ?? ""), String(address.postalCode ?? "")].filter(Boolean).join(", ");
17730
+ }).join("; ");
17731
+ }
17424
17732
  var UUID_REFERENCE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
17425
17733
  function formatReferenceLabel(identifier, label, subject = "Reference") {
17426
17734
  if (identifier == null || identifier === "") return `${subject} unavailable`;
17427
17735
  if (typeof label === "string" && label.trim() && !UUID_REFERENCE.test(label.trim())) return label;
17428
17736
  return `${subject} reference not resolved`;
17429
17737
  }
17738
+ var UNRESOLVED_REFERENCE_LABEL = / (?:unavailable|reference not resolved)$/;
17739
+ function ownershipPhrase(ownerLabel, ownerType, role) {
17740
+ const text2 = (value) => typeof value === "string" && value.trim() ? value.trim() : void 0;
17741
+ const name = text2(ownerLabel) && !UNRESOLVED_REFERENCE_LABEL.test(text2(ownerLabel)) ? text2(ownerLabel) : void 0;
17742
+ const type = text2(ownerType)?.replace(/[_-]+/g, " ");
17743
+ const parts = name ? [`Owned by ${name}`, type, text2(role)] : type ? [`${type.charAt(0).toUpperCase()}${type.slice(1)}-owned`, text2(role)] : [];
17744
+ return parts.filter(Boolean).join(" \xB7 ") || void 0;
17745
+ }
17430
17746
  function formatRecordLabel(value) {
17431
17747
  return typeof value === "string" && UUID_REFERENCE.test(value.trim()) ? "Record name unavailable" : String(value ?? "");
17432
17748
  }
@@ -17748,7 +18064,7 @@ function validateComponentIntakeDocument(input) {
17748
18064
  if (!Array.isArray(document.rows)) return [...errors, "intake rows must be an array"];
17749
18065
  const ids = document.rows.map((row) => row && typeof row === "object" && !Array.isArray(row) && typeof row.id === "string" ? row.id : "");
17750
18066
  if (ids.some((id) => id.length === 0)) errors.push("every intake row must have a non-empty id");
17751
- if (ids.length !== 112) errors.push(`intake must contain exactly 112 rows; received ${ids.length}`);
18067
+ if (ids.length !== 114) errors.push(`intake must contain exactly 114 rows; received ${ids.length}`);
17752
18068
  const uniqueCount = new Set(ids).size;
17753
18069
  if (uniqueCount !== ids.length) errors.push("intake IDs must be unique");
17754
18070
  const sorted = [...ids].sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
@@ -17791,6 +18107,7 @@ exports.VIZ_PREVIEW_TYPES = VIZ_PREVIEW_TYPES;
17791
18107
  exports.VIZ_SUMMARY_IDS = VIZ_SUMMARY_IDS;
17792
18108
  exports.VIZ_SVG_PROPS = VIZ_SVG_PROPS;
17793
18109
  exports.VIZ_THEME_SVG_PROPS = VIZ_THEME_SVG_PROPS;
18110
+ exports.addressCollectionSummary = addressCollectionSummary;
17794
18111
  exports.ariaSort = ariaSort;
17795
18112
  exports.assertStaticSvg = assertStaticSvg;
17796
18113
  exports.auditSummary = auditSummary;
@@ -17818,6 +18135,7 @@ exports.evaluateEmissionEligibility = evaluateEmissionEligibility;
17818
18135
  exports.evaluateFoundationV1 = evaluateFoundationV1;
17819
18136
  exports.formatBillingAmount = formatBillingAmount;
17820
18137
  exports.formatDateTime = formatDateTime;
18138
+ exports.formatDeclaredNumber = formatDeclaredNumber;
17821
18139
  exports.formatPriceAmount = formatPriceAmount;
17822
18140
  exports.formatPriceCode = formatPriceCode;
17823
18141
  exports.formatReadOnlyValue = formatReadOnlyValue;
@@ -17833,6 +18151,7 @@ exports.isGovernedComponent = isGovernedComponent;
17833
18151
  exports.isVizIntentFragment = isVizIntentFragment;
17834
18152
  exports.listStatuses = listStatuses;
17835
18153
  exports.nextSort = nextSort;
18154
+ exports.ownershipPhrase = ownershipPhrase;
17836
18155
  exports.parseBillingAmount = parseBillingAmount;
17837
18156
  exports.portedComponentContracts = portedComponentContracts;
17838
18157
  exports.portedScenarios = portedScenarios;