@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.js CHANGED
@@ -4,7 +4,7 @@ var component_intake_v1_default = {
4
4
  kind: "component-intake",
5
5
  baselineCommit: "ae560bc22969c1fd81336730be4330c9115fc316",
6
6
  planningCommit: "8ce349076e7e3ba3f0b2f3f667d4fbb5c6a4b63b",
7
- controllingObligationDenominator: 112,
7
+ controllingObligationDenominator: 114,
8
8
  countRule: "Derived from the unique, deterministically sorted rows array; never from an independent counter.",
9
9
  rows: [
10
10
  {
@@ -935,6 +935,38 @@ var component_intake_v1_default = {
935
935
  "traits/visual/Colorized.trait.yaml"
936
936
  ]
937
937
  },
938
+ {
939
+ id: "Combobox",
940
+ displayName: "Combobox",
941
+ baselineMetadata: {
942
+ categories: [
943
+ "primitive"
944
+ ],
945
+ tags: [
946
+ "autocomplete",
947
+ "combobox",
948
+ "field",
949
+ "filter",
950
+ "form",
951
+ "input",
952
+ "interactive",
953
+ "primitive",
954
+ "select"
955
+ ],
956
+ contexts: [
957
+ "form"
958
+ ],
959
+ regions: [
960
+ "form",
961
+ "main"
962
+ ]
963
+ },
964
+ intakeEvidence: [
965
+ "packages/component-contracts/src/contracts.ts#Combobox",
966
+ "packages/mcp-server/src/render/component-map.ts#renderCombobox"
967
+ ],
968
+ addedBy: "s223-m02; decision #2527 ruling 11"
969
+ },
938
970
  {
939
971
  id: "CommunicationDetailPanel",
940
972
  displayName: "CommunicationDetailPanel",
@@ -1920,6 +1952,37 @@ var component_intake_v1_default = {
1920
1952
  "traits/behavioral/Searchable.trait.yaml"
1921
1953
  ]
1922
1954
  },
1955
+ {
1956
+ id: "SegmentedControl",
1957
+ displayName: "SegmentedControl",
1958
+ baselineMetadata: {
1959
+ categories: [
1960
+ "primitive"
1961
+ ],
1962
+ tags: [
1963
+ "choice",
1964
+ "field",
1965
+ "form",
1966
+ "input",
1967
+ "interactive",
1968
+ "primitive",
1969
+ "radio",
1970
+ "segmented-control"
1971
+ ],
1972
+ contexts: [
1973
+ "form"
1974
+ ],
1975
+ regions: [
1976
+ "form",
1977
+ "main"
1978
+ ]
1979
+ },
1980
+ intakeEvidence: [
1981
+ "packages/component-contracts/src/contracts.ts#SegmentedControl",
1982
+ "packages/mcp-server/src/render/component-map.ts#renderSegmentedControl"
1983
+ ],
1984
+ addedBy: "s223-m02; decision #2527 ruling 10"
1985
+ },
1923
1986
  {
1924
1987
  id: "Select",
1925
1988
  displayName: "Select",
@@ -3226,9 +3289,9 @@ var component_reconciliation_proposed_v2_default = {
3226
3289
  baselineCommit: "a5638cf819bdadb86e2336c4aabe9b2184699c13",
3227
3290
  planningCommit: "8ce349076e7e3ba3f0b2f3f667d4fbb5c6a4b63b",
3228
3291
  status: "proposed-awaiting-approval",
3229
- controllingObligationDenominator: 112,
3292
+ controllingObligationDenominator: 114,
3230
3293
  approvedRuntimeCensus: null,
3231
- proposedRuntimeCensus: 112,
3294
+ proposedRuntimeCensus: 114,
3232
3295
  rows: [
3233
3296
  {
3234
3297
  id: "AddressCollectionPanel",
@@ -3868,6 +3931,25 @@ var component_reconciliation_proposed_v2_default = {
3868
3931
  implementationStatus: "implemented-evidence-complete",
3869
3932
  compatibilityNote: "Retain the named public ID and existing HTML discovery contract. Governed framework implementation and measurements are linked; classification remains a proposal."
3870
3933
  },
3934
+ {
3935
+ id: "Combobox",
3936
+ proposedClassification: "native",
3937
+ approvalState: "pending-approval",
3938
+ evidence: [
3939
+ "packages/mcp-server/src/render/component-map.ts#renderCombobox",
3940
+ "packages/components-react/evidence/react-readiness.v1.json#Combobox",
3941
+ "packages/components-vue/evidence/vue-readiness.v1.json#Combobox",
3942
+ "packages/component-contracts/src/contracts.ts#Combobox"
3943
+ ],
3944
+ implementationStatus: "implemented-evidence-complete",
3945
+ proposedResolution: {
3946
+ surface: "react+vue+html",
3947
+ implementation: "Combobox",
3948
+ source: "packages/component-contracts/src/contracts.ts",
3949
+ publicIdRetained: true
3950
+ },
3951
+ compatibilityNote: "New public identity added by decision #2527 (ruling 11). Governed framework implementation and measurements are linked; classification remains a proposal."
3952
+ },
3871
3953
  {
3872
3954
  id: "CommunicationDetailPanel",
3873
3955
  proposedClassification: "recipe",
@@ -4581,6 +4663,25 @@ var component_reconciliation_proposed_v2_default = {
4581
4663
  implementationStatus: "implemented-evidence-complete",
4582
4664
  compatibilityNote: "Retain the named public ID and existing HTML discovery contract. Governed framework implementation and measurements are linked; classification remains a proposal."
4583
4665
  },
4666
+ {
4667
+ id: "SegmentedControl",
4668
+ proposedClassification: "native",
4669
+ approvalState: "pending-approval",
4670
+ evidence: [
4671
+ "packages/mcp-server/src/render/component-map.ts#renderSegmentedControl",
4672
+ "packages/components-react/evidence/react-readiness.v1.json#SegmentedControl",
4673
+ "packages/components-vue/evidence/vue-readiness.v1.json#SegmentedControl",
4674
+ "packages/component-contracts/src/contracts.ts#SegmentedControl"
4675
+ ],
4676
+ implementationStatus: "implemented-evidence-complete",
4677
+ proposedResolution: {
4678
+ surface: "react+vue+html",
4679
+ implementation: "SegmentedControl",
4680
+ source: "packages/component-contracts/src/contracts.ts",
4681
+ publicIdRetained: true
4682
+ },
4683
+ compatibilityNote: "New public identity added by decision #2527 (ruling 10). Governed framework implementation and measurements are linked; classification remains a proposal."
4684
+ },
4584
4685
  {
4585
4686
  id: "Select",
4586
4687
  proposedClassification: "native",
@@ -5473,7 +5574,7 @@ var component_capability_ledger_v1_default = {
5473
5574
  schemaVersion: "1.0.0",
5474
5575
  kind: "component-capability-ledger",
5475
5576
  generatedAt: "2026-09-11T05:30:00Z",
5476
- controllingObligationDenominator: 112,
5577
+ controllingObligationDenominator: 114,
5477
5578
  approvedRuntimeCensus: null,
5478
5579
  source: "refresh_structured_data.py#project_measured_surfaces",
5479
5580
  rows: [
@@ -8182,6 +8283,77 @@ var component_capability_ledger_v1_default = {
8182
8283
  }
8183
8284
  }
8184
8285
  },
8286
+ {
8287
+ id: "Combobox",
8288
+ proposedClassification: "native",
8289
+ reconciliationState: "proposed-awaiting-approval",
8290
+ surfaces: {
8291
+ contract: {
8292
+ state: "versioned-v1",
8293
+ evidence: [
8294
+ "packages/component-contracts/src/contracts.ts#Combobox"
8295
+ ]
8296
+ },
8297
+ metadata: {
8298
+ state: "available",
8299
+ evidence: [
8300
+ "packages/component-contracts/registry/component-intake.v1.json#Combobox"
8301
+ ]
8302
+ },
8303
+ html: {
8304
+ state: "mapped",
8305
+ evidence: [
8306
+ "packages/mcp-server/src/render/component-map.ts#renderCombobox"
8307
+ ]
8308
+ },
8309
+ react: {
8310
+ state: "implemented-evidence-complete",
8311
+ evidence: [
8312
+ "packages/components-react/evidence/react-readiness.v1.json#Combobox"
8313
+ ]
8314
+ },
8315
+ vue: {
8316
+ state: "implemented-evidence-complete",
8317
+ evidence: [
8318
+ "packages/components-vue/evidence/vue-readiness.v1.json#Combobox"
8319
+ ]
8320
+ },
8321
+ generatedConsumer: {
8322
+ state: "unavailable",
8323
+ evidence: [
8324
+ "artifacts/product-reality/sprint-193/m07/runtime/runtime-cells.v1.json"
8325
+ ],
8326
+ reason: "No current runtime cell places this component; historical receipts do not establish current coverage."
8327
+ },
8328
+ accessibility: {
8329
+ state: "verified",
8330
+ evidence: [
8331
+ "artifacts/product-reality/sprint-223/m02/combobox/react-measured.json#Combobox",
8332
+ "artifacts/product-reality/sprint-223/m02/combobox/vue-measured.json#Combobox",
8333
+ "packages/components-react/evidence/react-readiness.v1.json#Combobox",
8334
+ "packages/components-vue/evidence/vue-readiness.v1.json#Combobox"
8335
+ ]
8336
+ },
8337
+ theme: {
8338
+ state: "verified",
8339
+ evidence: [
8340
+ "artifacts/product-reality/sprint-223/m02/combobox/react-theme/report.json#Combobox",
8341
+ "artifacts/product-reality/sprint-223/m02/combobox/vue-theme/report.json#Combobox",
8342
+ "packages/components-react/evidence/react-readiness.v1.json#Combobox",
8343
+ "packages/components-vue/evidence/vue-readiness.v1.json#Combobox"
8344
+ ]
8345
+ },
8346
+ interaction: {
8347
+ state: "verified",
8348
+ evidence: [
8349
+ "artifacts/product-reality/sprint-223/m02/combobox/react-measured.json#Combobox",
8350
+ "artifacts/product-reality/sprint-223/m02/combobox/vue-measured.json#Combobox",
8351
+ "packages/components-react/evidence/react-readiness.v1.json#Combobox",
8352
+ "packages/components-vue/evidence/vue-readiness.v1.json#Combobox"
8353
+ ]
8354
+ }
8355
+ }
8356
+ },
8185
8357
  {
8186
8358
  id: "CommunicationDetailPanel",
8187
8359
  proposedClassification: "recipe",
@@ -11233,6 +11405,77 @@ var component_capability_ledger_v1_default = {
11233
11405
  }
11234
11406
  }
11235
11407
  },
11408
+ {
11409
+ id: "SegmentedControl",
11410
+ proposedClassification: "native",
11411
+ reconciliationState: "proposed-awaiting-approval",
11412
+ surfaces: {
11413
+ contract: {
11414
+ state: "versioned-v1",
11415
+ evidence: [
11416
+ "packages/component-contracts/src/contracts.ts#SegmentedControl"
11417
+ ]
11418
+ },
11419
+ metadata: {
11420
+ state: "available",
11421
+ evidence: [
11422
+ "packages/component-contracts/registry/component-intake.v1.json#SegmentedControl"
11423
+ ]
11424
+ },
11425
+ html: {
11426
+ state: "mapped",
11427
+ evidence: [
11428
+ "packages/mcp-server/src/render/component-map.ts#renderSegmentedControl"
11429
+ ]
11430
+ },
11431
+ react: {
11432
+ state: "implemented-evidence-complete",
11433
+ evidence: [
11434
+ "packages/components-react/evidence/react-readiness.v1.json#SegmentedControl"
11435
+ ]
11436
+ },
11437
+ vue: {
11438
+ state: "implemented-evidence-complete",
11439
+ evidence: [
11440
+ "packages/components-vue/evidence/vue-readiness.v1.json#SegmentedControl"
11441
+ ]
11442
+ },
11443
+ generatedConsumer: {
11444
+ state: "unavailable",
11445
+ evidence: [
11446
+ "artifacts/product-reality/sprint-193/m07/runtime/runtime-cells.v1.json"
11447
+ ],
11448
+ reason: "No current runtime cell places this component; historical receipts do not establish current coverage."
11449
+ },
11450
+ accessibility: {
11451
+ state: "verified",
11452
+ evidence: [
11453
+ "artifacts/product-reality/sprint-223/m02/segmented-control/react-measured.json#SegmentedControl",
11454
+ "artifacts/product-reality/sprint-223/m02/segmented-control/vue-measured.json#SegmentedControl",
11455
+ "packages/components-react/evidence/react-readiness.v1.json#SegmentedControl",
11456
+ "packages/components-vue/evidence/vue-readiness.v1.json#SegmentedControl"
11457
+ ]
11458
+ },
11459
+ theme: {
11460
+ state: "verified",
11461
+ evidence: [
11462
+ "artifacts/product-reality/sprint-223/m02/segmented-control/react-theme/report.json#SegmentedControl",
11463
+ "artifacts/product-reality/sprint-223/m02/segmented-control/vue-theme/report.json#SegmentedControl",
11464
+ "packages/components-react/evidence/react-readiness.v1.json#SegmentedControl",
11465
+ "packages/components-vue/evidence/vue-readiness.v1.json#SegmentedControl"
11466
+ ]
11467
+ },
11468
+ interaction: {
11469
+ state: "verified",
11470
+ evidence: [
11471
+ "artifacts/product-reality/sprint-223/m02/segmented-control/react-measured.json#SegmentedControl",
11472
+ "artifacts/product-reality/sprint-223/m02/segmented-control/vue-measured.json#SegmentedControl",
11473
+ "packages/components-react/evidence/react-readiness.v1.json#SegmentedControl",
11474
+ "packages/components-vue/evidence/vue-readiness.v1.json#SegmentedControl"
11475
+ ]
11476
+ }
11477
+ }
11478
+ },
11236
11479
  {
11237
11480
  id: "Select",
11238
11481
  proposedClassification: "native",
@@ -15331,6 +15574,7 @@ var NUCLEUS_COMPONENT_IDS = [
15331
15574
  "ColorStatePicker",
15332
15575
  "ColorSwatch",
15333
15576
  "ColorizedBadge",
15577
+ "Combobox",
15334
15578
  "CommunicationDetailPanel",
15335
15579
  "CycleProgressCard",
15336
15580
  "DatePicker",
@@ -15366,6 +15610,7 @@ var NUCLEUS_COMPONENT_IDS = [
15366
15610
  "RoleAssignmentForm",
15367
15611
  "RoleBadgeList",
15368
15612
  "SearchInput",
15613
+ "SegmentedControl",
15369
15614
  "Select",
15370
15615
  "SortIndicator",
15371
15616
  "Stack",
@@ -15500,6 +15745,11 @@ var componentBehaviors = {
15500
15745
  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": [] },
15501
15746
  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": [] },
15502
15747
  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": [] },
15748
+ // s223-m02 (#2527 ruling 11): each trigger starts from the documented example (Canada chosen, the list closed). Tab reaches
15749
+ // the input; typing edits the filter text; Down opens the list at the first option and Up at the last (Japan, disabled,
15750
+ // is never reached); Home and End act on the list a key has opened; Enter picks the active option (France, after three
15751
+ // Downs); and Escape with the list closed clears the field and emits an empty value.
15752
+ 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": "" } }] },
15503
15753
  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": [] },
15504
15754
  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" } }] },
15505
15755
  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": [] },
@@ -15531,6 +15781,9 @@ var componentBehaviors = {
15531
15781
  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" }] },
15532
15782
  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": [] },
15533
15783
  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": "" } }] },
15784
+ // s223-m02 (#2527 ruling 10): the focus target is the checked radio, as Tabs names its tab; the radiogroup and its name
15785
+ // are asserted in each framework's scenario spec. The browser owns the keys, so each is a native radio-group move.
15786
+ 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" }] },
15534
15787
  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" }] },
15535
15788
  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": [] },
15536
15789
  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": [] },
@@ -15562,7 +15815,7 @@ var authoredContracts = {
15562
15815
  states: ["summary", "content"],
15563
15816
  tokenRoles: ["panel.background", "panel.border", "panel.title", "panel.subtitle"],
15564
15817
  accessibility: ["A real h3 heading names the panel section", "Subtitle and summary text remain visible beside the heading", "The panel is noninteractive"],
15565
- 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."
15818
+ 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."
15566
15819
  },
15567
15820
  AddressEditor: {
15568
15821
  id: "AddressEditor",
@@ -15597,17 +15850,17 @@ var authoredContracts = {
15597
15850
  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"],
15598
15851
  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."
15599
15852
  },
15600
- 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." },
15853
+ 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." },
15601
15854
  ArchivePill: {
15602
15855
  id: "ArchivePill",
15603
15856
  version: COMPONENT_CONTRACT_VERSION,
15604
- props: ["label", "text", "status", "state", "value", "variant", "tone", "emphasis", "isArchived"],
15857
+ props: ["label", "text", "status", "state", "value", "variant", "tone", "emphasis", "isArchived", "hideWhenFalse"],
15605
15858
  slots: ["default"],
15606
15859
  events: [],
15607
15860
  states: ["subtle", "solid"],
15608
15861
  tokenRoles: ["badge.background", "badge.text"],
15609
15862
  accessibility: ["false remains visible", "archive is the badge variant"],
15610
- 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."
15863
+ 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.'
15611
15864
  },
15612
15865
  ArchiveSummary: {
15613
15866
  id: "ArchiveSummary",
@@ -15745,15 +15998,15 @@ var authoredContracts = {
15745
15998
  CancellationBadge: {
15746
15999
  id: "CancellationBadge",
15747
16000
  version: COMPONENT_CONTRACT_VERSION,
15748
- props: ["label", "text", "status", "state", "value", "variant", "tone", "emphasis", "cancelAtPeriodEnd", "isCancelled"],
16001
+ props: ["label", "text", "status", "state", "value", "variant", "tone", "emphasis", "cancelAtPeriodEnd", "isCancelled", "hideWhenFalse"],
15749
16002
  slots: ["default"],
15750
16003
  events: [],
15751
16004
  states: ["subtle", "solid"],
15752
16005
  tokenRoles: ["badge.background", "badge.text"],
15753
16006
  accessibility: ["false remains visible", "cancellation is the badge variant"],
15754
- 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."
16007
+ 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.'
15755
16008
  },
15756
- 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." },
16009
+ 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)." },
15757
16010
  CancellationForm: {
15758
16011
  id: "CancellationForm",
15759
16012
  version: COMPONENT_CONTRACT_VERSION,
@@ -15867,6 +16120,25 @@ var authoredContracts = {
15867
16120
  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"],
15868
16121
  compatibility: "Mirrors renderColorizedBadge over renderBadgePrimitive label/status/color aliases and default variant colorized; Badge tone and emphasis retain their shared behavior."
15869
16122
  },
16123
+ // s223-m02 (#2527 ruling 11): pick one value from a list by typing to filter it, the WAI-ARIA combobox pattern with a
16124
+ // listbox popup. One markup in React, Vue and HTML; HTML's inline script gives it the same behaviour.
16125
+ Combobox: {
16126
+ id: "Combobox",
16127
+ version: COMPONENT_CONTRACT_VERSION,
16128
+ requiredProps: ["id", "label"],
16129
+ props: ["id", "label", "options", "value", "defaultValue", "placeholder", "name", "required", "disabled", "help", "validation", "size"],
16130
+ slots: ["label", "help", "validation"],
16131
+ events: ["change", "update"],
16132
+ states: ["closed", "open", "no-matches", "selected", "disabled", "invalid"],
16133
+ tokenRoles: ["input.background", "input.border", "input.text", "input.placeholder", "input.focus", "combobox.popup", "combobox.shadow", "combobox.option", "combobox.optionActive", "combobox.check", "field.message"],
16134
+ accessibility: [
16135
+ "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",
16136
+ "The visible label names the combobox and its listbox; help and error text describe the input",
16137
+ "The chosen option reports aria-selected and shows a check mark; a disabled option reports aria-disabled and is skipped",
16138
+ "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"
16139
+ ],
16140
+ 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.'
16141
+ },
15870
16142
  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." },
15871
16143
  CycleProgressCard: {
15872
16144
  id: "CycleProgressCard",
@@ -15912,7 +16184,7 @@ var authoredContracts = {
15912
16184
  states: ["open", "closed"],
15913
16185
  tokenRoles: ["dialog.background", "dialog.border", "dialog.shadow", "dialog.backdrop", "dialog.title", "dialog.description"],
15914
16186
  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"],
15915
- 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."
16187
+ 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."
15916
16188
  },
15917
16189
  FilterPanel: {
15918
16190
  id: "FilterPanel",
@@ -16042,13 +16314,13 @@ var authoredContracts = {
16042
16314
  OwnershipMeta: {
16043
16315
  id: "OwnershipMeta",
16044
16316
  version: COMPONENT_CONTRACT_VERSION,
16045
- props: ["title", "label", "heading", "name", "ownerType", "owner_type", "role", "ownershipRole"],
16317
+ props: ["title", "label", "heading", "name", "ownerType", "owner_type", "role", "ownershipRole", "ownerLabel"],
16046
16318
  slots: ["default"],
16047
16319
  events: [],
16048
16320
  states: ["populated", "empty"],
16049
16321
  tokenRoles: ["meta.text", "meta.label"],
16050
16322
  accessibility: ["metadata has inline term labels", "role is visible text not an ARIA role"],
16051
- 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."
16323
+ 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.'
16052
16324
  },
16053
16325
  OwnershipSummary: {
16054
16326
  id: "OwnershipSummary",
@@ -16271,6 +16543,19 @@ var authoredContracts = {
16271
16543
  accessibility: ["Native search input semantics", "Clear control has an accessible label"],
16272
16544
  compatibility: "Debounce and minimum-query settings preserve value updates across both targets."
16273
16545
  },
16546
+ // s223-m02 (#2527 ruling 10): one choice from two to five options, shown as joined segments.
16547
+ SegmentedControl: {
16548
+ id: "SegmentedControl",
16549
+ version: COMPONENT_CONTRACT_VERSION,
16550
+ requiredProps: ["id", "label"],
16551
+ props: ["id", "label", "options", "value", "defaultValue", "name", "size", "disabled"],
16552
+ slots: ["label"],
16553
+ events: ["change", "update"],
16554
+ states: ["selected", "unselected", "disabled"],
16555
+ tokenRoles: ["segmented.track", "segmented.selected", "segmented.ring", "segmented.text", "segmented.focus"],
16556
+ 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"],
16557
+ 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."
16558
+ },
16274
16559
  Select: {
16275
16560
  id: "Select",
16276
16561
  version: COMPONENT_CONTRACT_VERSION_1_1,
@@ -16296,7 +16581,7 @@ var authoredContracts = {
16296
16581
  accessibility: ["Does not alter child semantics"],
16297
16582
  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."
16298
16583
  },
16299
- 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." },
16584
+ 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)." },
16300
16585
  StatusBadge: {
16301
16586
  id: "StatusBadge",
16302
16587
  version: COMPONENT_CONTRACT_VERSION,
@@ -16376,7 +16661,7 @@ var authoredContracts = {
16376
16661
  states: ["off", "on", "disabled", "invalid"],
16377
16662
  tokenRoles: ["switch.track", "switch.thumb", "switch.border", "switch.focus", "field.message"],
16378
16663
  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"],
16379
- 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."
16664
+ 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.`
16380
16665
  },
16381
16666
  Table: {
16382
16667
  id: "Table",
@@ -16628,7 +16913,7 @@ var authoredScenarios = [
16628
16913
  { "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"] },
16629
16914
  { "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"] },
16630
16915
  { "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"] },
16631
- { "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"] },
16916
+ { "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"] },
16632
16917
  { "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"] },
16633
16918
  { "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"] },
16634
16919
  { "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"] },
@@ -16643,7 +16928,7 @@ var authoredScenarios = [
16643
16928
  { 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"] },
16644
16929
  { 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"] },
16645
16930
  { 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"] },
16646
- { 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"] },
16931
+ { 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"] },
16647
16932
  { 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"] },
16648
16933
  { 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"] },
16649
16934
  { 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"] },
@@ -16663,7 +16948,7 @@ var authoredScenarios = [
16663
16948
  { 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"] },
16664
16949
  { 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"] },
16665
16950
  { 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"] },
16666
- { 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"] },
16951
+ { 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"] },
16667
16952
  { 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"] },
16668
16953
  {
16669
16954
  id: "cancellation-summary-boolean",
@@ -16680,6 +16965,8 @@ var authoredScenarios = [
16680
16965
  // s222-m02 (#2502 ruling 11): the two components 0.4.0 adds. The dialog example is shown in place (modal false), as a
16681
16966
  // gallery shows it; modal true is the default.
16682
16967
  { 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"] },
16968
+ // s223-m02 (#2527 ruling 11): the combobox example; Japan is disabled, so the keyboard skips it and a click cannot pick it.
16969
+ { 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"] },
16683
16970
  { 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"] },
16684
16971
  { 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"] },
16685
16972
  { 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"] },
@@ -16700,7 +16987,7 @@ var authoredScenarios = [
16700
16987
  { 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"] },
16701
16988
  { 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"] },
16702
16989
  { 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"] },
16703
- { 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"] },
16990
+ { 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"] },
16704
16991
  { 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"] },
16705
16992
  {
16706
16993
  id: "pagination-bar-navigation",
@@ -16748,6 +17035,9 @@ var authoredScenarios = [
16748
17035
  renderExpectation: { name: "clear", trigger: "activate clear control", expected: "empty value emitted once" },
16749
17036
  assertions: ["input has search semantics", "clear control is named"]
16750
17037
  },
17038
+ // s223-m02 (#2527 ruling 10): the middle option is checked, so Tab landing on it shows the group's one tab stop is the
17039
+ // checked option, and both arrow directions have a neighbour.
17040
+ { 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"] },
16751
17041
  { 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"] },
16752
17042
  { 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"] },
16753
17043
  {
@@ -16878,7 +17168,8 @@ var STATUS_ICON_SHAPES = Object.freeze({
16878
17168
  undo: [path("M3 8a5 5 0 1 0 1.5-3.5"), path("M3 2.5v3h3")],
16879
17169
  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")],
16880
17170
  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")],
16881
- dot: [circle("8", "8", "2.5", true)]
17171
+ dot: [circle("8", "8", "2.5", true)],
17172
+ "chevron-down": [path("M4 6l4 4 4-4")]
16882
17173
  });
16883
17174
  var STATUS_ICON_SVG_ATTRS = Object.freeze({
16884
17175
  width: "1em",
@@ -17379,10 +17670,19 @@ function summaryValue(value) {
17379
17670
  function chronologicalEvents(events) {
17380
17671
  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);
17381
17672
  }
17382
- function formatReadOnlyValue(value, type, code = false) {
17673
+ function formatDeclaredNumber(value, format) {
17674
+ const number = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : NaN;
17675
+ if (!Number.isFinite(number)) return void 0;
17676
+ return format === "percent" ? new Intl.NumberFormat("en-US", { style: "percent", maximumFractionDigits: 2 }).format(number / 100) : new Intl.NumberFormat("en-US", { maximumFractionDigits: 2 }).format(number);
17677
+ }
17678
+ function formatReadOnlyValue(value, type, code = false, format) {
17383
17679
  if (value == null || value === "") return "Not recorded";
17384
17680
  if (type === "date" || type === "datetime") return formatDateTime(value) || "Invalid date";
17385
17681
  if (typeof value === "boolean") return value ? "Yes" : "No";
17682
+ if (format && !Array.isArray(value)) {
17683
+ const formatted = formatDeclaredNumber(value, format);
17684
+ if (formatted !== void 0) return formatted;
17685
+ }
17386
17686
  if (Array.isArray(value)) {
17387
17687
  if (value.some((item) => item !== null && typeof item === "object")) return `${value.length} ${value.length === 1 ? "record" : "records"}`;
17388
17688
  return value.map((item) => summaryValue(item) ?? "").join(", ") || "None recorded";
@@ -17419,12 +17719,28 @@ function recordCollectionEvents(record2, options = {}) {
17419
17719
  }
17420
17720
  return chronologicalEvents(events);
17421
17721
  }
17722
+ function addressCollectionSummary(entries) {
17723
+ const asRecord = (value) => value && typeof value === "object" ? value : {};
17724
+ return (Array.isArray(entries) ? entries : []).map((entry) => {
17725
+ const address = asRecord(asRecord(entry).address);
17726
+ const street = Array.isArray(address.addressLines) ? address.addressLines.map(String).join(", ") : "";
17727
+ return [asRecord(entry).role, street, String(address.locality ?? ""), String(address.administrativeArea ?? ""), String(address.postalCode ?? "")].filter(Boolean).join(", ");
17728
+ }).join("; ");
17729
+ }
17422
17730
  var UUID_REFERENCE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
17423
17731
  function formatReferenceLabel(identifier, label, subject = "Reference") {
17424
17732
  if (identifier == null || identifier === "") return `${subject} unavailable`;
17425
17733
  if (typeof label === "string" && label.trim() && !UUID_REFERENCE.test(label.trim())) return label;
17426
17734
  return `${subject} reference not resolved`;
17427
17735
  }
17736
+ var UNRESOLVED_REFERENCE_LABEL = / (?:unavailable|reference not resolved)$/;
17737
+ function ownershipPhrase(ownerLabel, ownerType, role) {
17738
+ const text2 = (value) => typeof value === "string" && value.trim() ? value.trim() : void 0;
17739
+ const name = text2(ownerLabel) && !UNRESOLVED_REFERENCE_LABEL.test(text2(ownerLabel)) ? text2(ownerLabel) : void 0;
17740
+ const type = text2(ownerType)?.replace(/[_-]+/g, " ");
17741
+ const parts = name ? [`Owned by ${name}`, type, text2(role)] : type ? [`${type.charAt(0).toUpperCase()}${type.slice(1)}-owned`, text2(role)] : [];
17742
+ return parts.filter(Boolean).join(" \xB7 ") || void 0;
17743
+ }
17428
17744
  function formatRecordLabel(value) {
17429
17745
  return typeof value === "string" && UUID_REFERENCE.test(value.trim()) ? "Record name unavailable" : String(value ?? "");
17430
17746
  }
@@ -17746,7 +18062,7 @@ function validateComponentIntakeDocument(input) {
17746
18062
  if (!Array.isArray(document.rows)) return [...errors, "intake rows must be an array"];
17747
18063
  const ids = document.rows.map((row) => row && typeof row === "object" && !Array.isArray(row) && typeof row.id === "string" ? row.id : "");
17748
18064
  if (ids.some((id) => id.length === 0)) errors.push("every intake row must have a non-empty id");
17749
- if (ids.length !== 112) errors.push(`intake must contain exactly 112 rows; received ${ids.length}`);
18065
+ if (ids.length !== 114) errors.push(`intake must contain exactly 114 rows; received ${ids.length}`);
17750
18066
  const uniqueCount = new Set(ids).size;
17751
18067
  if (uniqueCount !== ids.length) errors.push("intake IDs must be unique");
17752
18068
  const sorted = [...ids].sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
@@ -17760,4 +18076,4 @@ function getBaselineCapability(componentId) {
17760
18076
  return componentCapabilityBaseline.rows.find((row) => row.id === componentId);
17761
18077
  }
17762
18078
 
17763
- export { BILLING_AMOUNT_ERROR, BILLING_INTERVALS, BILLING_INTERVAL_ERROR, BILLING_MINOR_UNITS, COMPONENT_CLASSIFICATIONS, COMPONENT_CONTRACT_VERSION, COMPONENT_CONTRACT_VERSION_1_1, DEFAULT_COLOR_STATES, EMISSION_ELIGIBILITY_EVIDENCE_CLASSES, FOUNDATION_V1_EVIDENCE_CLASSES, GOVERNED_DEFINITION, GOVERNED_SURFACES, NO_LAST_PAYMENT, NO_NEXT_PAYMENT, NUCLEUS_COMPONENT_IDS, PORTED_COMPONENT_IDS, RESULT_STATES, RESULT_STATE_TONE, SEVERITY_TONES, STATUS_DOMAINS, STATUS_ICON_SHAPES, STATUS_ICON_SVG_ATTRS, UI_WORKFLOW_STATES, VIZ_CONTROL_IDS, VIZ_CONTROL_TITLES, VIZ_PREVIEW_TYPES, VIZ_SUMMARY_IDS, VIZ_SVG_PROPS, VIZ_THEME_SVG_PROPS, ariaSort, assertStaticSvg, auditSummary, billingAmountMessage, billingAmountText, billingCycle, billingDate, billingIntervalMessage, billingPaymentRows, billingPaymentSummary, billingPeriodEnd, billingSummary, chronologicalEvents, componentBehaviors, componentCapabilityBaseline, componentContracts, componentIntake, componentReconciliationProposal, currencyMinorUnits, dateTimeInputValue, defaultVizIntent, deriveStartingComponentCount, editVizIntent, evaluateEmissionEligibility, evaluateFoundationV1, formatBillingAmount, formatDateTime, formatPriceAmount, formatPriceCode, formatReadOnlyValue, formatRecordLabel, formatReferenceLabel, geoFieldMapping, getBannerToneTokenSet, getBaselineCapability, getStatusPresentation, getToneTokenSet, initialSort, isGovernedComponent, isVizIntentFragment, listStatuses, nextSort, parseBillingAmount, portedComponentContracts, portedScenarios, recipeItemLabels, recordCollectionEvents, relativeTimestampEmptyScenario, resolveStatusIcon, restartedBillingPeriod, sharedScenarios, statusIconMarkup, substitutionContractReport, summarizeSubstitutionReport, summaryValue, svgCarriesTitle, traitEventRows, validMinorUnits, validateComponentIntakeDocument, vizControlFields, vizFieldValue, vizPreviewLayers, vizSummaryRows };
18079
+ export { BILLING_AMOUNT_ERROR, BILLING_INTERVALS, BILLING_INTERVAL_ERROR, BILLING_MINOR_UNITS, COMPONENT_CLASSIFICATIONS, COMPONENT_CONTRACT_VERSION, COMPONENT_CONTRACT_VERSION_1_1, DEFAULT_COLOR_STATES, EMISSION_ELIGIBILITY_EVIDENCE_CLASSES, FOUNDATION_V1_EVIDENCE_CLASSES, GOVERNED_DEFINITION, GOVERNED_SURFACES, NO_LAST_PAYMENT, NO_NEXT_PAYMENT, NUCLEUS_COMPONENT_IDS, PORTED_COMPONENT_IDS, RESULT_STATES, RESULT_STATE_TONE, SEVERITY_TONES, STATUS_DOMAINS, STATUS_ICON_SHAPES, STATUS_ICON_SVG_ATTRS, UI_WORKFLOW_STATES, VIZ_CONTROL_IDS, VIZ_CONTROL_TITLES, VIZ_PREVIEW_TYPES, VIZ_SUMMARY_IDS, VIZ_SVG_PROPS, VIZ_THEME_SVG_PROPS, addressCollectionSummary, ariaSort, assertStaticSvg, auditSummary, billingAmountMessage, billingAmountText, billingCycle, billingDate, billingIntervalMessage, billingPaymentRows, billingPaymentSummary, billingPeriodEnd, billingSummary, chronologicalEvents, componentBehaviors, componentCapabilityBaseline, componentContracts, componentIntake, componentReconciliationProposal, currencyMinorUnits, dateTimeInputValue, defaultVizIntent, deriveStartingComponentCount, editVizIntent, evaluateEmissionEligibility, evaluateFoundationV1, formatBillingAmount, formatDateTime, formatDeclaredNumber, formatPriceAmount, formatPriceCode, formatReadOnlyValue, formatRecordLabel, formatReferenceLabel, geoFieldMapping, getBannerToneTokenSet, getBaselineCapability, getStatusPresentation, getToneTokenSet, initialSort, isGovernedComponent, isVizIntentFragment, listStatuses, nextSort, ownershipPhrase, parseBillingAmount, portedComponentContracts, portedScenarios, recipeItemLabels, recordCollectionEvents, relativeTimestampEmptyScenario, resolveStatusIcon, restartedBillingPeriod, sharedScenarios, statusIconMarkup, substitutionContractReport, summarizeSubstitutionReport, summaryValue, svgCarriesTitle, traitEventRows, validMinorUnits, validateComponentIntakeDocument, vizControlFields, vizFieldValue, vizPreviewLayers, vizSummaryRows };