@mhome/app-facade-protocol 1.112.2 → 1.114.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/README.md CHANGED
@@ -12,7 +12,10 @@ or forwarded by authenticated Cloud ingress. The separate Hub `/local/*`
12
12
  protocol carries domain input and never uses the public envelope.
13
13
 
14
14
  Every `/app/*` request uses the strict `FacadeCall` envelope. Invocation
15
- metadata lives in `control`; the domain request lives in `input`. The crate
15
+ metadata lives in `control`; the domain request lives in `input`. Optional
16
+ `source` hints identify the originating surface without selecting actor or authority.
17
+ See [household behavior recording](contract/household-recording-v1.md) for the
18
+ shared projection contract and runtime ownership. The crate
16
19
  owns public targets, request/response/event schemas, and stable operation
17
20
  identity. Core-to-Node routes and provider runtime models belong to
18
21
  `mhome-core-api` instead.
@@ -0,0 +1,61 @@
1
+ # Household behavior records
2
+
3
+ This is input for background household learning, not an audit log. Plugin Facades,
4
+ queries, UI layout, account settings, infrastructure and Agent memory updates skip.
5
+ `manifest/recording.v1.json` owns the explicit Facade projections and canonical
6
+ Device command allowlist (including declared provider overrides). Mixed-purpose
7
+ hooks may return Skip. New Facades default to Skip until explicitly registered.
8
+ Rust `recording::project` and Lion `BehaviorProjection` implement the same pure
9
+ hooks and share `fixtures/recording.conformance.json`. The Lion runtime definition
10
+ is a packaged mirror verified against this canonical manifest in joint-source tests.
11
+
12
+ A call may carry optional `source: {kind, page?, cardId?}` beside `control` and
13
+ `input`. Kinds are `ui`, `agent` (built-in Agent), `messaging`, `cli`, `skill`, `mcp`.
14
+ Source hints never select authorization or actor. Trusted Agent/MCP ingress overrides
15
+ hints; a canonical Messaging Agent surface keeps `messaging`, including through
16
+ Cloud-to-Hub forwarding. CLI defaults to `cli`; external Skills explicitly pass
17
+ `meow --source skill`. UI sets `ui`. `appClientId` comes only from the verified
18
+ Client identity, not connection routing IDs or an input hint.
19
+
20
+ The runtime derives actor from verified initiation: User -> `{kind: user,userId}`;
21
+ shared Space -> `{kind: space}`. The record schema also reserves `{kind: agent}`
22
+ for autonomous initiation. Current user-directed Agent operations retain their
23
+ verified principal. Source `agent` never makes an operation autonomous. Wiring a
24
+ future proactive scheduler requires trusted initiation metadata; an LLM cannot
25
+ self-declare an actor in the Facade call.
26
+
27
+ Only actual execution records. Prepare, reject, validation before execution and
28
+ cached commit replay do not. Internal automation side effects are separate event
29
+ sources, not additional manual behavior. The record uses one `id`: trusted delegated
30
+ operation identity, prepared operation identity when applicable, or a generated UUID.
31
+ It contains `occurredAtMs` (server UTC at execution dispatch), `finishedAtMs` (server
32
+ UTC when that dispatch settles), actor, source and domain `data`. Status comes from
33
+ the canonical Full outcome before Essential presentation. An accepted async run is
34
+ not a claim that all its physical effects completed. Failures keep intent and error
35
+ code, never raw exception messages, internal details, complete request/response or
36
+ source scripts. Runtime completion/Twin observations belong to their own sources.
37
+
38
+ Space mode determines the single storage owner: Local -> Hub SQLite, Cloud ->
39
+ Lion's configured cloud store. Routing/forwarding creates no second record.
40
+ The existing Space cleanup removes this partition. Hub queued deliveries retain
41
+ the existing runtime fence so revoked/replaced generations cannot recreate records
42
+ after cleanup; Cloud writes use the existing Space admission guard.
43
+ The physical row has `pk`, `sk`, `schemaVersion=1`, `payloadYaml` only:
44
+
45
+ - `pk = tenant|space`.
46
+ - `sk = zero-padded 13-digit UTC milliseconds|id`.
47
+ - Fixed string order supports `[start,end)` queries in one partition. Pagination
48
+ uses the last returned SK exclusively. No secondary index is required.
49
+ - Inserts never replace an existing key. Retrying persistence reuses the same row.
50
+ - YAML retains null, false, zero and typed values; no custom tags or raw JSON copy.
51
+
52
+ Recording is best effort. Request code only captures immutable facts and offers
53
+ work to a bounded queue (256). Projection, YAML and storage run in the background.
54
+ Failures, overload and the 32 KiB projected-payload limit drop/count the record,
55
+ without changing the business result or replaying the operation. No durable outbox,
56
+ start-record requirement, recovery workflow, or logging warning in Facade responses.
57
+
58
+ Core adds a table to its complete SQLite baseline. An existing incompatible Dev
59
+ DB requires the explicit standard rebuild workflow; startup never rewrites migration
60
+ checksums, deletes data or silently migrates the old baseline. Publishing Foundation
61
+ and reconciling normal consumer protocol receipts remain release prerequisites.
@@ -0,0 +1,393 @@
1
+ [
2
+ {
3
+ "target": "/app/widget/data/update",
4
+ "input": {
5
+ "widgetId": "lamp-d",
6
+ "typedValue": 0,
7
+ "internal": "secret"
8
+ },
9
+ "outcome": {
10
+ "status": "success"
11
+ },
12
+ "expected": {
13
+ "event": "widget.value.set",
14
+ "widgetId": "lamp-d",
15
+ "typedValue": 0,
16
+ "status": "success"
17
+ }
18
+ },
19
+ {
20
+ "target": "/app/widget/data/update",
21
+ "input": {
22
+ "widgetId": "lamp-d",
23
+ "typedValue": null
24
+ },
25
+ "outcome": {
26
+ "status": "error",
27
+ "error": {
28
+ "code": "UNREACHABLE",
29
+ "message": "private",
30
+ "details": {
31
+ "token": "secret"
32
+ }
33
+ }
34
+ },
35
+ "expected": {
36
+ "event": "widget.value.set",
37
+ "widgetId": "lamp-d",
38
+ "typedValue": null,
39
+ "status": "error",
40
+ "errorCode": "UNREACHABLE"
41
+ }
42
+ },
43
+ {
44
+ "target": "/app/widget/delete",
45
+ "input": {
46
+ "widgetIds": [
47
+ "x-d",
48
+ "wake-c"
49
+ ]
50
+ },
51
+ "outcome": {
52
+ "status": "success"
53
+ },
54
+ "expected": {
55
+ "event": "circadian.deleted",
56
+ "widgetIds": [
57
+ "wake-c"
58
+ ],
59
+ "status": "success"
60
+ }
61
+ },
62
+ {
63
+ "target": "/app/widget/delete",
64
+ "input": {
65
+ "widgetIds": [
66
+ "x-d"
67
+ ]
68
+ },
69
+ "outcome": {
70
+ "status": "success"
71
+ },
72
+ "expected": null
73
+ },
74
+ {
75
+ "target": "/app/widget/circadian/config/update",
76
+ "input": {
77
+ "widgetId": "wake-c",
78
+ "displayName": "Wake"
79
+ },
80
+ "outcome": {
81
+ "status": "success"
82
+ },
83
+ "expected": null
84
+ },
85
+ {
86
+ "target": "/app/widget/circadian/runtime/update",
87
+ "input": {
88
+ "widgetId": "wake-c",
89
+ "offset": 0,
90
+ "multiplier": 1
91
+ },
92
+ "outcome": {
93
+ "status": "success"
94
+ },
95
+ "expected": {
96
+ "event": "circadian.adjusted",
97
+ "widgetId": "wake-c",
98
+ "offset": 0,
99
+ "multiplier": 1,
100
+ "status": "success"
101
+ }
102
+ },
103
+ {
104
+ "target": "/app/automation/start",
105
+ "input": {
106
+ "automationId": "a",
107
+ "timezone": "Asia/Shanghai"
108
+ },
109
+ "outcome": {
110
+ "status": "success",
111
+ "data": {
112
+ "enabled": true,
113
+ "running": false
114
+ }
115
+ },
116
+ "expected": {
117
+ "event": "automation.start",
118
+ "automationId": "a",
119
+ "enabled": true,
120
+ "running": false,
121
+ "status": "success"
122
+ }
123
+ },
124
+ {
125
+ "target": "/app/dialog/reply",
126
+ "input": {
127
+ "dialogId": "d",
128
+ "value": {
129
+ "choice": false
130
+ }
131
+ },
132
+ "outcome": {
133
+ "status": "success",
134
+ "data": {
135
+ "accepted": true,
136
+ "dialog": {
137
+ "images": [
138
+ "private"
139
+ ]
140
+ }
141
+ }
142
+ },
143
+ "expected": {
144
+ "event": "dialog.answered",
145
+ "dialogId": "d",
146
+ "value": {
147
+ "choice": false
148
+ },
149
+ "accepted": true,
150
+ "status": "success"
151
+ }
152
+ },
153
+ {
154
+ "target": "/app/capability/invoke/json",
155
+ "input": {
156
+ "capabilityId": "mlinkHue.device.command.onOff",
157
+ "request": {
158
+ "device": "device1",
159
+ "command": "off",
160
+ "internal": "secret"
161
+ }
162
+ },
163
+ "outcome": {
164
+ "status": "partial",
165
+ "data": {}
166
+ },
167
+ "expected": {
168
+ "event": "device.command",
169
+ "capabilityId": "mlinkHue.device.command.onOff",
170
+ "parameters": {
171
+ "device": "device1",
172
+ "command": "off"
173
+ },
174
+ "status": "partial"
175
+ }
176
+ },
177
+ {
178
+ "target": "/app/capability/invoke",
179
+ "input": {
180
+ "capabilityId": "basic.device.command.onOff",
181
+ "request": "device: lamp\ncommand: 'off'"
182
+ },
183
+ "outcome": {
184
+ "status": "success"
185
+ },
186
+ "expected": {
187
+ "event": "device.command",
188
+ "capabilityId": "basic.device.command.onOff",
189
+ "parameters": {
190
+ "device": "lamp",
191
+ "command": "off"
192
+ },
193
+ "status": "success"
194
+ }
195
+ },
196
+ {
197
+ "target": "/app/device/disable",
198
+ "input": {},
199
+ "outcome": {
200
+ "status": "success"
201
+ },
202
+ "expected": null
203
+ },
204
+ {
205
+ "target": "/app/room/rename",
206
+ "input": {},
207
+ "outcome": {
208
+ "status": "success"
209
+ },
210
+ "expected": null
211
+ },
212
+ {
213
+ "target": "/app/plugin/camera/device/settings/update",
214
+ "input": {},
215
+ "outcome": {
216
+ "status": "success"
217
+ },
218
+ "expected": null
219
+ },
220
+ {
221
+ "target": "/app/agent/memory/save",
222
+ "input": {},
223
+ "outcome": {
224
+ "status": "success"
225
+ },
226
+ "expected": null
227
+ },
228
+ {
229
+ "target": "/app/automation/list",
230
+ "input": {},
231
+ "outcome": {
232
+ "status": "success"
233
+ },
234
+ "expected": null
235
+ },
236
+ {
237
+ "target": "/app/capability/invoke/json",
238
+ "input": {
239
+ "capabilityId": "basic.device.command.getImageSnapshot",
240
+ "request": {}
241
+ },
242
+ "outcome": {
243
+ "status": "success"
244
+ },
245
+ "expected": null
246
+ },
247
+ {
248
+ "target": "/app/capability/invoke/json",
249
+ "input": {
250
+ "capabilityId": "basic.device.command.prepareWebrtcSession",
251
+ "request": {}
252
+ },
253
+ "outcome": {
254
+ "status": "success"
255
+ },
256
+ "expected": null
257
+ },
258
+ {
259
+ "target": "/app/capability/invoke/json",
260
+ "input": {
261
+ "capabilityId": "basic.device.command.identify",
262
+ "request": {}
263
+ },
264
+ "outcome": {
265
+ "status": "success"
266
+ },
267
+ "expected": null
268
+ },
269
+ {
270
+ "target": "/app/capability/invoke/json",
271
+ "input": {
272
+ "capabilityId": "basic.device.command.onOff",
273
+ "request": {
274
+ "device": {
275
+ "uid": "lamp",
276
+ "name": "Desk lamp",
277
+ "attributes": {
278
+ "private": "hidden"
279
+ }
280
+ },
281
+ "command": "on"
282
+ }
283
+ },
284
+ "outcome": {
285
+ "status": "success"
286
+ },
287
+ "expected": {
288
+ "event": "device.command",
289
+ "capabilityId": "basic.device.command.onOff",
290
+ "parameters": {
291
+ "device": {
292
+ "uid": "lamp",
293
+ "name": "Desk lamp"
294
+ },
295
+ "command": "on"
296
+ },
297
+ "status": "success"
298
+ }
299
+ },
300
+ {
301
+ "target": "/app/presentation/automation/copy",
302
+ "input": {
303
+ "automationId": "old",
304
+ "name": "Bedtime"
305
+ },
306
+ "outcome": {
307
+ "status": "success",
308
+ "data": {
309
+ "automationId": "new"
310
+ }
311
+ },
312
+ "expected": {
313
+ "event": "automation.copy",
314
+ "fromAutomationId": "old",
315
+ "automationId": "new",
316
+ "name": "Bedtime",
317
+ "status": "success"
318
+ }
319
+ },
320
+ {
321
+ "target": "/app/capability/invoke",
322
+ "input": {
323
+ "capabilityId": "basic.device.command.onOff",
324
+ "request": "device: lamp\ncommand: on"
325
+ },
326
+ "outcome": {
327
+ "status": "success"
328
+ },
329
+ "expected": {
330
+ "event": "device.command",
331
+ "capabilityId": "basic.device.command.onOff",
332
+ "parameters": {
333
+ "device": "lamp",
334
+ "command": "on"
335
+ },
336
+ "status": "success"
337
+ }
338
+ },
339
+ {
340
+ "target": "/app/capability/invoke",
341
+ "input": {
342
+ "capabilityId": "basic.device.command.setBrightness",
343
+ "request": "device: lamp\nbrightness: 08"
344
+ },
345
+ "outcome": {
346
+ "status": "success"
347
+ },
348
+ "expected": {
349
+ "event": "device.command",
350
+ "capabilityId": "basic.device.command.setBrightness",
351
+ "parameters": {
352
+ "device": "lamp",
353
+ "brightness": "08"
354
+ },
355
+ "status": "success"
356
+ }
357
+ },
358
+ {
359
+ "target": "/app/capability/invoke",
360
+ "input": {
361
+ "capabilityId": "basic.device.command.setBrightness",
362
+ "request": "device: lamp\nbrightness: 010"
363
+ },
364
+ "outcome": {
365
+ "status": "success"
366
+ },
367
+ "expected": {
368
+ "event": "device.command",
369
+ "capabilityId": "basic.device.command.setBrightness",
370
+ "parameters": {
371
+ "device": "lamp",
372
+ "brightness": "010"
373
+ },
374
+ "status": "success"
375
+ }
376
+ },
377
+ {
378
+ "target": "/app/widget/circadian/config/update",
379
+ "input": {
380
+ "widget_id": "w-c",
381
+ "location_id": "home"
382
+ },
383
+ "outcome": {
384
+ "status": "success"
385
+ },
386
+ "expected": {
387
+ "event": "circadian.configured",
388
+ "widgetId": "w-c",
389
+ "locationId": "home",
390
+ "status": "success"
391
+ }
392
+ }
393
+ ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.app-facade.v1",
3
- "contractVersion": "1.112.2",
3
+ "contractVersion": "1.114.1",
4
4
  "callSchema": "schema/facade-call.v1.schema.json",
5
5
  "routing": "manifest/routing.v1.json",
6
6
  "routingSchema": "schema/routing.v1.schema.json",
@@ -1,5 +1,5 @@
1
1
  {
2
- "contractVersion": "1.112.2",
2
+ "contractVersion": "1.114.1",
3
3
  "operations": {
4
4
  "/app/agent/context/get": "spaceRead",
5
5
  "/app/agent/credit/usage": "spaceRead",
@@ -331,8 +331,6 @@
331
331
  "/identity/node/list": "spaceManage",
332
332
  "/identity/node/onboarding/start": "spaceManage",
333
333
  "/identity/node/revoke": "spaceManage",
334
- "/integration/composite/refresh": "spaceWrite",
335
- "/integration/providerEnv/refresh": "spaceWrite",
336
334
  "/llm/asr/transcribe": "spaceWrite",
337
335
  "/llm/capabilities": "spaceRead",
338
336
  "/llm/decision/decide": "spaceWrite",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.host-provision.targets.v1",
3
- "contractVersion": "1.112.2",
3
+ "contractVersion": "1.114.1",
4
4
  "contract": "contract/host-provisioning-v1.md",
5
5
  "localTargets": [
6
6
  "/local/host/provision/start",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.hub.targets.v1",
3
- "contractVersion": "1.112.2",
3
+ "contractVersion": "1.114.1",
4
4
  "appTargets": [
5
5
  "/app/hub/get",
6
6
  "/app/hub/remove",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.pod.targets.v1",
3
- "contractVersion": "1.112.2",
3
+ "contractVersion": "1.114.1",
4
4
  "contract": "contract/pod-commissioning-v1.md",
5
5
  "localTargets": [
6
6
  "/local/pod/discovery/start",
@@ -0,0 +1,465 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "operations": [
4
+ {
5
+ "target": "/app/capability/invoke",
6
+ "event": "device.command",
7
+ "input": [],
8
+ "output": [],
9
+ "hook": "capability"
10
+ },
11
+ {
12
+ "target": "/app/capability/invoke/json",
13
+ "event": "device.command",
14
+ "input": [],
15
+ "output": [],
16
+ "hook": "capability"
17
+ },
18
+ {
19
+ "target": "/app/widget/data/update",
20
+ "event": "widget.value.set",
21
+ "input": [
22
+ "widgetId",
23
+ "typedValue",
24
+ "value",
25
+ "values"
26
+ ],
27
+ "output": []
28
+ },
29
+ {
30
+ "target": "/app/widget/button/trigger",
31
+ "event": "widget.button.pressed",
32
+ "input": [
33
+ "widgetId",
34
+ "clickType"
35
+ ],
36
+ "output": []
37
+ },
38
+ {
39
+ "target": "/app/widget/circadian/runtime/update",
40
+ "event": "circadian.adjusted",
41
+ "input": [
42
+ "widgetId",
43
+ "curve",
44
+ "offset",
45
+ "multiplier"
46
+ ],
47
+ "output": []
48
+ },
49
+ {
50
+ "target": "/app/automation/start",
51
+ "event": "automation.start",
52
+ "input": [
53
+ "automationId"
54
+ ],
55
+ "output": [
56
+ "enabled",
57
+ "running"
58
+ ]
59
+ },
60
+ {
61
+ "target": "/app/automation/stop",
62
+ "event": "automation.stop",
63
+ "input": [
64
+ "automationId"
65
+ ],
66
+ "output": [
67
+ "enabled",
68
+ "running"
69
+ ]
70
+ },
71
+ {
72
+ "target": "/app/presentation/automation/generated/enable",
73
+ "event": "automation.enable",
74
+ "input": [
75
+ "automationId"
76
+ ],
77
+ "output": [
78
+ "automationId",
79
+ "enabled",
80
+ "running"
81
+ ]
82
+ },
83
+ {
84
+ "target": "/app/presentation/automation/generated/disable",
85
+ "event": "automation.disable",
86
+ "input": [
87
+ "automationId"
88
+ ],
89
+ "output": [
90
+ "automationId",
91
+ "enabled",
92
+ "running"
93
+ ]
94
+ },
95
+ {
96
+ "target": "/app/presentation/automation/generated/run",
97
+ "event": "automation.run",
98
+ "input": [
99
+ "automationId"
100
+ ],
101
+ "output": [
102
+ "automationId",
103
+ "enabled",
104
+ "running"
105
+ ]
106
+ },
107
+ {
108
+ "target": "/app/quickword/run",
109
+ "event": "quickword.invoked",
110
+ "input": [
111
+ "quickWord",
112
+ "values"
113
+ ],
114
+ "output": [
115
+ "dispatched"
116
+ ]
117
+ },
118
+ {
119
+ "target": "/app/dialog/reply",
120
+ "event": "dialog.answered",
121
+ "input": [
122
+ "dialogId",
123
+ "value"
124
+ ],
125
+ "output": [
126
+ "accepted"
127
+ ]
128
+ },
129
+ {
130
+ "target": "/app/automation/save",
131
+ "event": "automation.saved",
132
+ "input": [
133
+ "automationId",
134
+ "singleUse",
135
+ "restoreEnabled"
136
+ ],
137
+ "output": [
138
+ "automationId"
139
+ ],
140
+ "hook": "automationSource"
141
+ },
142
+ {
143
+ "target": "/app/presentation/automation/overview/save",
144
+ "event": "automation.saved",
145
+ "input": [
146
+ "automationId"
147
+ ],
148
+ "output": [
149
+ "automationId",
150
+ "enabled"
151
+ ]
152
+ },
153
+ {
154
+ "target": "/app/presentation/automation/copy",
155
+ "event": "automation.copy",
156
+ "input": [
157
+ "name"
158
+ ],
159
+ "output": [
160
+ "automationId"
161
+ ],
162
+ "hook": "automationCopy"
163
+ },
164
+ {
165
+ "target": "/app/presentation/automation/enroll",
166
+ "event": "automation.enroll",
167
+ "input": [
168
+ "name"
169
+ ],
170
+ "output": [
171
+ "automationId"
172
+ ],
173
+ "hook": "automationCopy"
174
+ },
175
+ {
176
+ "target": "/app/automation/delete",
177
+ "event": "automation.deleted",
178
+ "input": [
179
+ "automationId",
180
+ "automationIds"
181
+ ],
182
+ "output": []
183
+ },
184
+ {
185
+ "target": "/app/automation/snapshot/rollback",
186
+ "event": "automation.restored",
187
+ "input": [
188
+ "automationId",
189
+ "snapshotId"
190
+ ],
191
+ "output": [
192
+ "automationId"
193
+ ]
194
+ },
195
+ {
196
+ "target": "/app/widget/circadian/create",
197
+ "event": "circadian.configured",
198
+ "input": [
199
+ "widgetId",
200
+ "locationId",
201
+ "schedules",
202
+ "curve",
203
+ "offset",
204
+ "multiplier"
205
+ ],
206
+ "output": [
207
+ "widgetId"
208
+ ],
209
+ "hook": "circadian"
210
+ },
211
+ {
212
+ "target": "/app/widget/circadian/config/update",
213
+ "event": "circadian.configured",
214
+ "input": [
215
+ "widgetId",
216
+ "locationId",
217
+ "schedules",
218
+ "curve",
219
+ "offset",
220
+ "multiplier"
221
+ ],
222
+ "output": [
223
+ "widgetId"
224
+ ],
225
+ "hook": "circadian"
226
+ },
227
+ {
228
+ "target": "/app/widget/delete",
229
+ "event": "circadian.deleted",
230
+ "input": [
231
+ "widgetIds"
232
+ ],
233
+ "output": [],
234
+ "hook": "circadianDelete"
235
+ }
236
+ ],
237
+ "deviceCommands": {
238
+ "onOff": [
239
+ "device",
240
+ "command"
241
+ ],
242
+ "setBrightness": [
243
+ "device",
244
+ "brightness",
245
+ "transitionDuration"
246
+ ],
247
+ "setColorTemperature": [
248
+ "device",
249
+ "colorTemperature",
250
+ "transitionDuration"
251
+ ],
252
+ "setColorRGB": [
253
+ "device",
254
+ "hue",
255
+ "saturation",
256
+ "transitionDuration"
257
+ ],
258
+ "setThermostatTemperature": [
259
+ "device",
260
+ "coolingSetpoint",
261
+ "heatingSetpoint"
262
+ ],
263
+ "setThermostatMode": [
264
+ "device",
265
+ "hvacMode",
266
+ "presetMode"
267
+ ],
268
+ "setFan": [
269
+ "device",
270
+ "mode",
271
+ "speed"
272
+ ],
273
+ "coverOpenClose": [
274
+ "device",
275
+ "command",
276
+ "position",
277
+ "transitionDuration"
278
+ ],
279
+ "lockUnlock": [
280
+ "device",
281
+ "command"
282
+ ],
283
+ "playMedia": [
284
+ "device",
285
+ "providerMediaContentId",
286
+ "mediaContent"
287
+ ],
288
+ "controlMediaPlayback": [
289
+ "device",
290
+ "command"
291
+ ],
292
+ "seekMediaPlayback": [
293
+ "device",
294
+ "position"
295
+ ],
296
+ "setAudioVolume": [
297
+ "device",
298
+ "volume"
299
+ ],
300
+ "setAudioMute": [
301
+ "device",
302
+ "command"
303
+ ],
304
+ "broadcastAudio": [
305
+ "device",
306
+ "audio",
307
+ "volume",
308
+ "priority"
309
+ ],
310
+ "chime": [
311
+ "device",
312
+ "command"
313
+ ],
314
+ "dispensePetFood": [
315
+ "device",
316
+ "portions",
317
+ "weight"
318
+ ],
319
+ "cameraPtz": [
320
+ "device",
321
+ "command",
322
+ "preset",
323
+ "speed",
324
+ "duration"
325
+ ],
326
+ "setCameraRecording": [
327
+ "device",
328
+ "mode"
329
+ ],
330
+ "setCameraSetting": [
331
+ "device",
332
+ "monitoringMode",
333
+ "personRecognitionMode"
334
+ ],
335
+ "startAudioRecording": [
336
+ "device"
337
+ ],
338
+ "stopAudioRecording": [
339
+ "device"
340
+ ]
341
+ },
342
+ "deviceCapabilities": {
343
+ "audioBridge.device.command.broadcastAudio": "broadcastAudio",
344
+ "audioBridge.device.command.controlMediaPlayback": "controlMediaPlayback",
345
+ "audioBridge.device.command.playMedia": "playMedia",
346
+ "audioBridge.device.command.seekMediaPlayback": "seekMediaPlayback",
347
+ "audioBridge.device.command.setAudioMute": "setAudioMute",
348
+ "audioBridge.device.command.setAudioVolume": "setAudioVolume",
349
+ "audioBridge.device.command.startAudioRecording": "startAudioRecording",
350
+ "audioBridge.device.command.stopAudioRecording": "stopAudioRecording",
351
+ "basic.device.command.broadcastAudio": "broadcastAudio",
352
+ "basic.device.command.cameraPtz": "cameraPtz",
353
+ "basic.device.command.chime": "chime",
354
+ "basic.device.command.controlMediaPlayback": "controlMediaPlayback",
355
+ "basic.device.command.coverOpenClose": "coverOpenClose",
356
+ "basic.device.command.dispensePetFood": "dispensePetFood",
357
+ "basic.device.command.lockUnlock": "lockUnlock",
358
+ "basic.device.command.onOff": "onOff",
359
+ "basic.device.command.playMedia": "playMedia",
360
+ "basic.device.command.seekMediaPlayback": "seekMediaPlayback",
361
+ "basic.device.command.setAudioMute": "setAudioMute",
362
+ "basic.device.command.setAudioVolume": "setAudioVolume",
363
+ "basic.device.command.setBrightness": "setBrightness",
364
+ "basic.device.command.setCameraRecording": "setCameraRecording",
365
+ "basic.device.command.setCameraSetting": "setCameraSetting",
366
+ "basic.device.command.setColorRGB": "setColorRGB",
367
+ "basic.device.command.setColorTemperature": "setColorTemperature",
368
+ "basic.device.command.setFan": "setFan",
369
+ "basic.device.command.setThermostatMode": "setThermostatMode",
370
+ "basic.device.command.setThermostatTemperature": "setThermostatTemperature",
371
+ "basic.device.command.startAudioRecording": "startAudioRecording",
372
+ "basic.device.command.stopAudioRecording": "stopAudioRecording",
373
+ "camera.device.command.cameraPtz": "cameraPtz",
374
+ "camera.device.command.onOff": "onOff",
375
+ "camera.device.command.setCameraSetting": "setCameraSetting",
376
+ "mlinkGoogleCast.device.command.broadcastAudio": "broadcastAudio",
377
+ "mlinkGoogleCast.device.command.controlMediaPlayback": "controlMediaPlayback",
378
+ "mlinkGoogleCast.device.command.playMedia": "playMedia",
379
+ "mlinkGoogleCast.device.command.setAudioMute": "setAudioMute",
380
+ "mlinkGoogleCast.device.command.setAudioVolume": "setAudioVolume",
381
+ "mlinkHomeAssistant.device.command.broadcastAudio": "broadcastAudio",
382
+ "mlinkHomeAssistant.device.command.chime": "chime",
383
+ "mlinkHomeAssistant.device.command.controlMediaPlayback": "controlMediaPlayback",
384
+ "mlinkHomeAssistant.device.command.coverOpenClose": "coverOpenClose",
385
+ "mlinkHomeAssistant.device.command.lockUnlock": "lockUnlock",
386
+ "mlinkHomeAssistant.device.command.onOff": "onOff",
387
+ "mlinkHomeAssistant.device.command.playMedia": "playMedia",
388
+ "mlinkHomeAssistant.device.command.setAudioMute": "setAudioMute",
389
+ "mlinkHomeAssistant.device.command.setAudioVolume": "setAudioVolume",
390
+ "mlinkHomeAssistant.device.command.setBrightness": "setBrightness",
391
+ "mlinkHomeAssistant.device.command.setColorRGB": "setColorRGB",
392
+ "mlinkHomeAssistant.device.command.setColorTemperature": "setColorTemperature",
393
+ "mlinkHomeAssistant.device.command.setFan": "setFan",
394
+ "mlinkHomeAssistant.device.command.setThermostatMode": "setThermostatMode",
395
+ "mlinkHomeAssistant.device.command.setThermostatTemperature": "setThermostatTemperature",
396
+ "mlinkHue.device.command.onOff": "onOff",
397
+ "mlinkHue.device.command.setBrightness": "setBrightness",
398
+ "mlinkHue.device.command.setColorRGB": "setColorRGB",
399
+ "mlinkHue.device.command.setColorTemperature": "setColorTemperature",
400
+ "mlinkLutron.device.command.coverOpenClose": "coverOpenClose",
401
+ "mlinkLutron.device.command.onOff": "onOff",
402
+ "mlinkLutron.device.command.setBrightness": "setBrightness",
403
+ "mlinkLutron.device.command.setFan": "setFan",
404
+ "mlinkMatter.device.command.coverOpenClose": "coverOpenClose",
405
+ "mlinkMatter.device.command.lockUnlock": "lockUnlock",
406
+ "mlinkMatter.device.command.onOff": "onOff",
407
+ "mlinkMatter.device.command.setAudioMute": "setAudioMute",
408
+ "mlinkMatter.device.command.setAudioVolume": "setAudioVolume",
409
+ "mlinkMatter.device.command.setBrightness": "setBrightness",
410
+ "mlinkMatter.device.command.setColorRGB": "setColorRGB",
411
+ "mlinkMatter.device.command.setColorTemperature": "setColorTemperature",
412
+ "mlinkMatter.device.command.setFan": "setFan",
413
+ "mlinkMatter.device.command.setThermostatMode": "setThermostatMode",
414
+ "mlinkMatter.device.command.setThermostatTemperature": "setThermostatTemperature",
415
+ "mlinkShelly.device.command.coverOpenClose": "coverOpenClose",
416
+ "mlinkShelly.device.command.onOff": "onOff",
417
+ "mlinkShelly.device.command.setBrightness": "setBrightness",
418
+ "mlinkShelly.device.command.setColorRGB": "setColorRGB",
419
+ "mlinkShelly.device.command.setColorTemperature": "setColorTemperature",
420
+ "mlinkSmartThings.device.command.broadcastAudio": "broadcastAudio",
421
+ "mlinkSmartThings.device.command.chime": "chime",
422
+ "mlinkSmartThings.device.command.controlMediaPlayback": "controlMediaPlayback",
423
+ "mlinkSmartThings.device.command.coverOpenClose": "coverOpenClose",
424
+ "mlinkSmartThings.device.command.lockUnlock": "lockUnlock",
425
+ "mlinkSmartThings.device.command.onOff": "onOff",
426
+ "mlinkSmartThings.device.command.setAudioMute": "setAudioMute",
427
+ "mlinkSmartThings.device.command.setAudioVolume": "setAudioVolume",
428
+ "mlinkSmartThings.device.command.setBrightness": "setBrightness",
429
+ "mlinkSmartThings.device.command.setColorRGB": "setColorRGB",
430
+ "mlinkSmartThings.device.command.setColorTemperature": "setColorTemperature",
431
+ "mlinkSmartThings.device.command.setFan": "setFan",
432
+ "mlinkSmartThings.device.command.setThermostatMode": "setThermostatMode",
433
+ "mlinkSmartThings.device.command.setThermostatTemperature": "setThermostatTemperature",
434
+ "mlinkSonos.device.command.broadcastAudio": "broadcastAudio",
435
+ "mlinkSonos.device.command.controlMediaPlayback": "controlMediaPlayback",
436
+ "mlinkSonos.device.command.playMedia": "playMedia",
437
+ "mlinkSonos.device.command.setAudioMute": "setAudioMute",
438
+ "mlinkSonos.device.command.setAudioVolume": "setAudioVolume",
439
+ "playground.device.command.broadcastAudio": "broadcastAudio",
440
+ "playground.device.command.chime": "chime",
441
+ "playground.device.command.controlMediaPlayback": "controlMediaPlayback",
442
+ "playground.device.command.coverOpenClose": "coverOpenClose",
443
+ "playground.device.command.lockUnlock": "lockUnlock",
444
+ "playground.device.command.onOff": "onOff",
445
+ "playground.device.command.playMedia": "playMedia",
446
+ "playground.device.command.setAudioMute": "setAudioMute",
447
+ "playground.device.command.setAudioVolume": "setAudioVolume",
448
+ "playground.device.command.setBrightness": "setBrightness",
449
+ "playground.device.command.setColorRGB": "setColorRGB",
450
+ "playground.device.command.setColorTemperature": "setColorTemperature",
451
+ "playground.device.command.setFan": "setFan",
452
+ "playground.device.command.setThermostatMode": "setThermostatMode",
453
+ "playground.device.command.setThermostatTemperature": "setThermostatTemperature",
454
+ "smartLife.device.command.onOff": "onOff",
455
+ "smartLife.device.command.setBrightness": "setBrightness",
456
+ "smartLife.device.command.setColorRGB": "setColorRGB",
457
+ "smartLife.device.command.setColorTemperature": "setColorTemperature",
458
+ "smartLife.device.command.setFan": "setFan",
459
+ "xiaomi.device.command.onOff": "onOff",
460
+ "xiaomi.device.command.setBrightness": "setBrightness",
461
+ "xiaomi.device.command.setColorRGB": "setColorRGB",
462
+ "xiaomi.device.command.setColorTemperature": "setColorTemperature",
463
+ "xiaomi.device.command.setFan": "setFan"
464
+ }
465
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.app-facade.routing.v1",
3
- "contractVersion": "1.112.2",
3
+ "contractVersion": "1.114.1",
4
4
  "targetPrefix": "/app/",
5
5
  "default": {
6
6
  "execution": "scopeMode"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.messaging.targets.v1",
3
- "contractVersion": "1.112.2",
3
+ "contractVersion": "1.114.1",
4
4
  "requestTargets": [
5
5
  "/app/messaging/provider/list",
6
6
  "/app/messaging/provider-account/list",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhome/app-facade-protocol",
3
- "version": "1.112.2",
3
+ "version": "1.114.1",
4
4
  "description": "Build-time protocol artifacts for mhome.app-facade",
5
5
  "license": "MIT",
6
6
  "repository": {
package/protocol.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "protocol": "mhome.app-facade",
3
- "contractVersion": "1.112.2",
3
+ "contractVersion": "1.114.1",
4
4
  "manifest": "manifest/app-facade.v1.json",
5
5
  "schemas": {
6
6
  "storage": "schema/storage.v1.schema.json",
7
+ "householdRecording": "schema/household-recording.v1.schema.json",
7
8
  "nowAttention": "schema/now-attention.v1.schema.json",
8
9
  "billing": "schema/billing.v1.schema.json",
9
10
  "pluginInstall": "schema/plugin-install.v1.schema.json",
@@ -4,44 +4,158 @@
4
4
  "title": "App Facade call",
5
5
  "type": "object",
6
6
  "additionalProperties": false,
7
- "required": ["control", "input"],
7
+ "required": [
8
+ "control",
9
+ "input"
10
+ ],
8
11
  "properties": {
9
12
  "control": {
10
13
  "type": "object",
11
14
  "additionalProperties": false,
12
- "required": ["mode"],
15
+ "required": [
16
+ "mode"
17
+ ],
13
18
  "properties": {
14
- "mode": { "enum": ["direct", "prepare", "commit", "reject"] },
15
- "preparedActionId": { "type": "string", "minLength": 1, "pattern": ".*\\S.*" },
16
- "approvalToken": { "type": "string", "minLength": 1, "pattern": ".*\\S.*" },
17
- "responseDetail": { "enum": ["full", "essential"] }
19
+ "mode": {
20
+ "enum": [
21
+ "direct",
22
+ "prepare",
23
+ "commit",
24
+ "reject"
25
+ ]
26
+ },
27
+ "preparedActionId": {
28
+ "type": "string",
29
+ "minLength": 1,
30
+ "pattern": ".*\\S.*"
31
+ },
32
+ "approvalToken": {
33
+ "type": "string",
34
+ "minLength": 1,
35
+ "pattern": ".*\\S.*"
36
+ },
37
+ "responseDetail": {
38
+ "enum": [
39
+ "full",
40
+ "essential"
41
+ ]
42
+ }
18
43
  },
19
44
  "allOf": [
20
45
  {
21
- "if": { "properties": { "mode": { "enum": ["direct", "prepare"] } } },
46
+ "if": {
47
+ "properties": {
48
+ "mode": {
49
+ "enum": [
50
+ "direct",
51
+ "prepare"
52
+ ]
53
+ }
54
+ }
55
+ },
22
56
  "then": {
23
57
  "not": {
24
58
  "anyOf": [
25
- { "properties": { "preparedActionId": {} }, "required": ["preparedActionId"] },
26
- { "properties": { "approvalToken": {} }, "required": ["approvalToken"] }
59
+ {
60
+ "properties": {
61
+ "preparedActionId": {}
62
+ },
63
+ "required": [
64
+ "preparedActionId"
65
+ ]
66
+ },
67
+ {
68
+ "properties": {
69
+ "approvalToken": {}
70
+ },
71
+ "required": [
72
+ "approvalToken"
73
+ ]
74
+ }
27
75
  ]
28
76
  }
29
77
  }
30
78
  },
31
79
  {
32
- "if": { "properties": { "mode": { "const": "commit" } } },
33
- "then": { "properties": { "preparedActionId": {}, "approvalToken": {} }, "required": ["preparedActionId", "approvalToken"] }
80
+ "if": {
81
+ "properties": {
82
+ "mode": {
83
+ "const": "commit"
84
+ }
85
+ }
86
+ },
87
+ "then": {
88
+ "properties": {
89
+ "preparedActionId": {},
90
+ "approvalToken": {}
91
+ },
92
+ "required": [
93
+ "preparedActionId",
94
+ "approvalToken"
95
+ ]
96
+ }
34
97
  },
35
98
  {
36
- "if": { "properties": { "mode": { "const": "reject" } } },
99
+ "if": {
100
+ "properties": {
101
+ "mode": {
102
+ "const": "reject"
103
+ }
104
+ }
105
+ },
37
106
  "then": {
38
- "properties": { "preparedActionId": {} },
39
- "required": ["preparedActionId"],
40
- "not": { "properties": { "approvalToken": {} }, "required": ["approvalToken"] }
107
+ "properties": {
108
+ "preparedActionId": {}
109
+ },
110
+ "required": [
111
+ "preparedActionId"
112
+ ],
113
+ "not": {
114
+ "properties": {
115
+ "approvalToken": {}
116
+ },
117
+ "required": [
118
+ "approvalToken"
119
+ ]
120
+ }
41
121
  }
42
122
  }
43
123
  ]
44
124
  },
45
- "input": true
125
+ "input": true,
126
+ "source": {
127
+ "type": [
128
+ "object",
129
+ "null"
130
+ ],
131
+ "additionalProperties": false,
132
+ "required": [
133
+ "kind"
134
+ ],
135
+ "properties": {
136
+ "kind": {
137
+ "enum": [
138
+ "ui",
139
+ "agent",
140
+ "messaging",
141
+ "cli",
142
+ "skill",
143
+ "mcp"
144
+ ]
145
+ },
146
+ "page": {
147
+ "type": [
148
+ "string",
149
+ "null"
150
+ ]
151
+ },
152
+ "cardId": {
153
+ "type": [
154
+ "string",
155
+ "null"
156
+ ]
157
+ }
158
+ }
159
+ }
46
160
  }
47
161
  }
@@ -0,0 +1,129 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Household behavior record",
4
+ "type": "object",
5
+ "additionalProperties": false,
6
+ "required": [
7
+ "id",
8
+ "occurredAtMs",
9
+ "finishedAtMs",
10
+ "actor",
11
+ "source",
12
+ "data"
13
+ ],
14
+ "properties": {
15
+ "id": {
16
+ "type": "string",
17
+ "minLength": 1
18
+ },
19
+ "occurredAtMs": {
20
+ "type": "integer",
21
+ "minimum": 0
22
+ },
23
+ "finishedAtMs": {
24
+ "type": "integer",
25
+ "minimum": 0
26
+ },
27
+ "actor": {
28
+ "oneOf": [
29
+ {
30
+ "type": "object",
31
+ "additionalProperties": false,
32
+ "required": [
33
+ "kind",
34
+ "userId"
35
+ ],
36
+ "properties": {
37
+ "kind": {
38
+ "const": "user"
39
+ },
40
+ "userId": {
41
+ "type": "string",
42
+ "minLength": 1
43
+ }
44
+ }
45
+ },
46
+ {
47
+ "type": "object",
48
+ "additionalProperties": false,
49
+ "required": [
50
+ "kind"
51
+ ],
52
+ "properties": {
53
+ "kind": {
54
+ "const": "space"
55
+ }
56
+ }
57
+ },
58
+ {
59
+ "type": "object",
60
+ "additionalProperties": false,
61
+ "required": [
62
+ "kind"
63
+ ],
64
+ "properties": {
65
+ "kind": {
66
+ "const": "agent"
67
+ },
68
+ "agentId": {
69
+ "type": "string"
70
+ }
71
+ }
72
+ }
73
+ ]
74
+ },
75
+ "source": {
76
+ "type": "object",
77
+ "required": [
78
+ "kind"
79
+ ],
80
+ "properties": {
81
+ "kind": {
82
+ "enum": [
83
+ "ui",
84
+ "agent",
85
+ "messaging",
86
+ "cli",
87
+ "skill",
88
+ "mcp"
89
+ ]
90
+ },
91
+ "appClientId": {
92
+ "type": "string"
93
+ },
94
+ "page": {
95
+ "type": "string"
96
+ },
97
+ "cardId": {
98
+ "type": "string"
99
+ },
100
+ "surfaceId": {
101
+ "type": "string"
102
+ },
103
+ "provider": {
104
+ "type": "string"
105
+ }
106
+ }
107
+ },
108
+ "data": {
109
+ "type": "object",
110
+ "required": [
111
+ "event",
112
+ "status"
113
+ ],
114
+ "properties": {
115
+ "event": {
116
+ "type": "string"
117
+ },
118
+ "status": {
119
+ "enum": [
120
+ "success",
121
+ "partial",
122
+ "error",
123
+ "cancelled"
124
+ ]
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }