@mhome/app-facade-protocol 1.113.0 → 1.115.0

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,78 @@
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. Direct Messaging Dialog replies use the verified external sender
17
+ and a Messaging-only forwarding binding; they create no Agent run and can only invoke
18
+ `/app/dialog/reply` in direct mode. CLI defaults to `cli`; external Skills explicitly pass
19
+ `meow --source skill`. UI sets `ui`. `appClientId` comes only from the verified
20
+ Client identity, not connection routing IDs or an input hint.
21
+
22
+ The runtime derives actor from verified initiation: User -> `{kind: user,userId}`;
23
+ shared Space -> `{kind: space}`. The record schema also reserves `{kind: agent}`
24
+ for autonomous initiation. Current user-directed Agent operations retain their
25
+ verified principal. Source `agent` never makes an operation autonomous. Wiring a
26
+ future proactive scheduler requires trusted initiation metadata; an LLM cannot
27
+ self-declare an actor in the Facade call.
28
+
29
+ Only actual execution records. Prepare, reject, validation before execution and
30
+ cached commit replay do not. Internal automation side effects are separate event
31
+ sources, not additional manual behavior. The record uses one `id`: trusted delegated
32
+ operation identity, prepared operation identity when applicable, or a generated UUID.
33
+ It contains `occurredAtMs` (server UTC at execution dispatch), `finishedAtMs` (server
34
+ UTC when that dispatch settles), actor, source and domain `data`. Status comes from
35
+ the canonical Full outcome before Essential presentation. An accepted async run is
36
+ not a claim that all its physical effects completed. Failures keep intent and error
37
+ code, never raw exception messages, internal details, complete request/response or
38
+ source scripts. Runtime completion/Twin observations belong to their own sources.
39
+
40
+ Facades may contribute frozen business facts through an execution-scoped hook. The
41
+ hook runs in the background writer and cannot replace canonical event/status/error
42
+ fields. Automation save and Overview save contribute the resolved YAML document
43
+ already obtained by the business flow. Their projection keeps name, description,
44
+ root `$` parameter values and input-variable references; task/action bodies, compiler
45
+ models, attached scripts and diagnostics are excluded. Hook failure leaves the
46
+ business response unchanged.
47
+
48
+ Space mode determines the single storage owner: Local -> Hub SQLite, Cloud ->
49
+ Lion's configured cloud store. Routing/forwarding creates no second record.
50
+ The existing Space cleanup removes this partition. Hub queued deliveries retain
51
+ the existing runtime fence so revoked/replaced generations cannot recreate records
52
+ after cleanup. Cloud writers register with Space admission before reading the
53
+ authoritative Space identity; only ACTIVE Cloud Spaces accept queued records.
54
+ Terminal deletion marks the identity first, drains admitted work, then deletes the
55
+ partition, so other instances and delayed queue entries cannot recreate it.
56
+ The physical row has `pk`, `sk`, `schemaVersion=1`, `payloadYaml` only:
57
+
58
+ - `pk = tenant|space`.
59
+ - `sk = zero-padded 13-digit UTC milliseconds|id`.
60
+ - Fixed string order supports `[start,end)` queries in one partition. Pagination
61
+ uses the last returned SK exclusively. No secondary index is required.
62
+ - Inserts never replace an existing key. Retrying persistence reuses the same row.
63
+ - `household/behavior` participates in ordinary Cloud/Hub DataSync. Mode switches
64
+ merge immutable rows, preserve original keys/schema/YAML bytes, reject foreign
65
+ partitions and conflicting existing rows, and rely on the existing successful
66
+ import acknowledgement before source cleanup. A retry does not clear history.
67
+ - YAML retains null, false, zero and typed values; no custom tags or raw JSON copy.
68
+
69
+ Recording is best effort. Request code only captures immutable facts and offers
70
+ work to a bounded queue (256). Projection, YAML and storage run in the background.
71
+ Failures, overload and the 32 KiB projected-payload limit drop/count the record,
72
+ without changing the business result or replaying the operation. No durable outbox,
73
+ start-record requirement, recovery workflow, or logging warning in Facade responses.
74
+
75
+ Core adds a table to its complete SQLite baseline. An existing incompatible Dev
76
+ DB requires the explicit standard rebuild workflow; startup never rewrites migration
77
+ checksums, deletes data or silently migrates the old baseline. Publishing Foundation
78
+ and reconciling normal consumer protocol receipts remain release prerequisites.
@@ -0,0 +1,28 @@
1
+ [
2
+ {
3
+ "source": "name: Bedtime\ndescription: Good night\ninputVars:\n - name: $time\n type: Time\n description: Bedtime\n internal: omit\n$time: \"23:00\"\n$enabled: false\n$count: 0\n$reset: null\ntask: internal-code\nscripts: secret-source\n",
4
+ "expected": {
5
+ "definition": {
6
+ "name": "Bedtime",
7
+ "description": "Good night",
8
+ "inputVariables": [
9
+ {
10
+ "name": "$time",
11
+ "type": "Time",
12
+ "description": "Bedtime"
13
+ }
14
+ ],
15
+ "parameters": {
16
+ "$time": "23:00",
17
+ "$enabled": false,
18
+ "$count": 0,
19
+ "$reset": null
20
+ }
21
+ }
22
+ }
23
+ },
24
+ {
25
+ "source": "task: internal-code",
26
+ "expected": null
27
+ }
28
+ ]
@@ -0,0 +1,6 @@
1
+ {
2
+ "pk": "t|s",
3
+ "sk": "0000000000100|on",
4
+ "schemaVersion": 1,
5
+ "payloadYaml": "id: on\noccurredAtMs: 100\nfinishedAtMs: 105\nactor:\n kind: user\n userId: user\nsource:\n kind: ui\ndata:\n event: widget.value.set\n status: success\n widgetId: w-d\n typedValue: false\n"
6
+ }