@mhome/app-facade-protocol 1.85.0 → 1.89.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 +8 -4
- package/contract/card-skins-v1.md +63 -41
- package/contract/host-provisioning-v1.md +39 -26
- package/contract/now-attention-v1.md +56 -0
- package/fixtures/attention/conformance.json +263 -0
- package/fixtures/authorization/decisions.json +88 -0
- package/fixtures/card-skins/space.json +6 -3
- package/fixtures/presentation/cases.json +222 -51
- package/fixtures/routing/cases.json +32 -0
- package/manifest/app-facade.v1.json +35 -27
- package/manifest/attention-policy.v1.json +18 -0
- package/manifest/authorization.v1.json +16 -15
- package/manifest/host-provision-targets.v1.json +1 -1
- package/manifest/hub-targets.v1.json +1 -1
- package/manifest/pod-targets.v1.json +1 -1
- package/manifest/presentation-times.v1.json +12 -0
- package/manifest/routing.v1.json +4 -3
- package/manifest/targets.v1.json +1 -1
- package/package.json +1 -1
- package/protocol.json +3 -1
- package/schema/card-skin-package.v1.schema.json +13 -1
- package/schema/card-skins.v1.schema.json +49 -7
- package/schema/now-attention.v1.schema.json +259 -0
package/README.md
CHANGED
|
@@ -81,10 +81,11 @@ are separate from this result envelope.
|
|
|
81
81
|
|
|
82
82
|
App UI requests full and preserves the complete envelope through transport and SDK
|
|
83
83
|
parsing. UI consumers explicitly read data and handle warnings and non-success outcomes.
|
|
84
|
-
Essential YAML
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
Essential YAML preserves all values selected by the domain projection, including
|
|
85
|
+
explicit business nulls in resource values, histories and diagnostic details.
|
|
86
|
+
Domains explicitly omit optional configuration fields when appropriate; the serializer
|
|
87
|
+
never guesses whether null means absence. False, zero, strings, empty collections and
|
|
88
|
+
array positions are preserved. This is output-only; it
|
|
88
89
|
never changes request semantics, stored data or prepared actions.
|
|
89
90
|
|
|
90
91
|
Agent and MCP public results use essential; internal workflow reads use full. The CLI
|
|
@@ -264,3 +265,6 @@ Cloud-owned content uses an object-store signed URL; local content is read from
|
|
|
264
265
|
owning Hub on demand. External resolution creates no cloud replica and cannot
|
|
265
266
|
make an offline local owner readable. The current inline Hub bridge size limit
|
|
266
267
|
still applies. Local file download remains a client workflow over ordinary resolve.
|
|
268
|
+
|
|
269
|
+
Agent Profile Markdown image ownership and canonical read-back are specified in
|
|
270
|
+
[Agent Profile media](contract/agent-profile-media-v1.md).
|
|
@@ -8,15 +8,17 @@ identity come exclusively from authenticated ingress, never from domain input.
|
|
|
8
8
|
|
|
9
9
|
## Catalog and publication
|
|
10
10
|
|
|
11
|
-
`/app/
|
|
11
|
+
`/app/ui/customize/cards/catalog/*` always executes in Cloud. Catalog reads require a
|
|
12
12
|
User principal. Package creation reserves `packageId` in that tenant. Only the
|
|
13
13
|
stored author may edit its display metadata or publish versions. Authorship is
|
|
14
|
-
immutable.
|
|
14
|
+
immutable. Creation requires `baseUi` (for example `default` or `default-pod`).
|
|
15
|
+
The package keeps this base across all versions; prepare and complete reject a
|
|
16
|
+
manifest with another base. Package lookup is by known package ID; this is not a public marketplace
|
|
15
17
|
or a searchable cross-tenant catalog.
|
|
16
18
|
|
|
17
19
|
| Target suffix | Input definition | Output |
|
|
18
20
|
| --- | --- | --- |
|
|
19
|
-
| `catalog/package/get` | `packageGet` | `{revision, value: {packageId, authorUserId, name, description, createdAt}}` |
|
|
21
|
+
| `catalog/package/get` | `packageGet` | `{revision, value: {packageId, baseUi, authorUserId, name, description, createdAt}}` |
|
|
20
22
|
| `catalog/package/create` | `packageCreate` | `{}` |
|
|
21
23
|
| `catalog/package/update` | `packageUpdate` | `{}` |
|
|
22
24
|
| `catalog/release/get` | `releaseGet` | `{id, baseUrl, manifest}` |
|
|
@@ -34,35 +36,44 @@ only supported asset extensions with their exact media type, size and SHA-256.
|
|
|
34
36
|
Schema draft-07, with only fragment `$ref`s, no `$async`, and at most 64 levels.
|
|
35
37
|
Each config root must have `type: object`.
|
|
36
38
|
|
|
37
|
-
Each prepared session binds
|
|
38
|
-
It expires after 15 minutes.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
release.
|
|
48
|
-
winning completion returns
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
39
|
+
Each prepared session binds a manifest, authenticated author and immutable delivery directory.
|
|
40
|
+
It expires after 15 minutes. Each file's returned URL and exact headers authorize a direct
|
|
41
|
+
S3/OSS PUT to a private staging key, binding its size and forbidding overwrite. Upload grants
|
|
42
|
+
are temporary secrets and are not persisted in the publishing session. Staging is outside
|
|
43
|
+
CloudFront's readable origin prefix. No App HTTP endpoint relays upload or download bytes.
|
|
44
|
+
|
|
45
|
+
Complete checks ownership and expiry, then reads the actual staged bytes with the declared
|
|
46
|
+
size plus one byte as a hard bound. Size, SHA-256 and completeness must match the manifest;
|
|
47
|
+
uploader-supplied object metadata is not an integrity receipt. The exact verified bytes are
|
|
48
|
+
written with create-only semantics to a separate published prefix. Only after all files
|
|
49
|
+
succeed can a create-only release become visible. Concurrent sessions for one version have
|
|
50
|
+
one winner. Retrying that winning completion returns its exact release even after expiry.
|
|
51
|
+
A failed completion may leave unreferenced objects, never a partial installable release.
|
|
52
|
+
|
|
53
|
+
Published `baseUrl` is a stable HTTPS directory under the configured static origin, for
|
|
54
|
+
example `https://static.mhome.ai/ui/cards/<namespace>/<package>/<version>/<deliveryId>/`.
|
|
55
|
+
CloudFront reads only the `published/` storage prefix and supplies CORS, correct media types,
|
|
56
|
+
`nosniff` and immutable caching. Temporary uploads use `staging/`, which CDN readers cannot
|
|
57
|
+
access. There is no expiring download signature in a release. Possession of a delivery URL
|
|
58
|
+
permits reading its public executable bytes; catalog and upload authority remain separate.
|
|
59
|
+
Config values stay in the Space selection and secrets must not enter card packages.
|
|
60
|
+
|
|
61
|
+
Web loads compiled modules from the static origin. Native clients may resolve a release to
|
|
62
|
+
verified local package files through a host-only resource port. Such runtime resource URLs
|
|
63
|
+
are never persisted in Catalog or Space selection records and do not alter release identity.
|
|
64
|
+
Package caching does not install, select, upgrade, or grant additional device authority.
|
|
65
|
+
All platforms retain the renderer isolation requirement, including for cached files.
|
|
60
66
|
|
|
61
67
|
The publication service validates metadata and bytes, not JavaScript behavior.
|
|
68
|
+
The renderer contract remains `apiVersion: 1` during development and changes in
|
|
69
|
+
place. Hosts and skins use that current contract without a compatibility layer.
|
|
62
70
|
The authoring build verifies the bundled ESM structure; the browser host verifies
|
|
63
|
-
renderer exports against the manifest before using them.
|
|
64
|
-
|
|
65
|
-
|
|
71
|
+
renderer exports against the manifest before using them. Each base owns its
|
|
72
|
+
presentation adapter and renderer host; common card state and actions do not
|
|
73
|
+
require a common rendering technology. Hosts must enforce their execution
|
|
74
|
+
boundary before enabling external code. A manifest or publication grants no
|
|
75
|
+
general App privileges, SDK access or native bridge access. Publication is not a
|
|
76
|
+
claim of runtime isolation, a malicious-code audit or browser SRI enforcement.
|
|
66
77
|
|
|
67
78
|
## Space selection
|
|
68
79
|
|
|
@@ -86,19 +97,23 @@ been created; otherwise it must equal the latest read token. A stale token retur
|
|
|
86
97
|
non-null revision. Mutation responses acknowledge the write; read the selection
|
|
87
98
|
again for its latest state/revision, which may include another writer's edit.
|
|
88
99
|
|
|
89
|
-
Install
|
|
100
|
+
Install requires the target `baseUi`, a known package ID and exact version; the service resolves the
|
|
90
101
|
published release from the tenant catalog. Core uses its authenticated cloud
|
|
91
102
|
bridge for that read. Neither accepts client-provided release IDs, manifests or
|
|
92
|
-
URLs.
|
|
103
|
+
URLs. The release base must equal the requested base. Installation records include
|
|
104
|
+
that base and must match their pinned release. Installation does not
|
|
105
|
+
automatically enable pattern overrides. Each package
|
|
93
106
|
has one installation per Space; installing another version uses `upgrade`.
|
|
94
107
|
|
|
95
|
-
Set override selects an
|
|
96
|
-
the supplied config against its schema. Reset removes
|
|
97
|
-
|
|
108
|
+
Set override requires `baseUi` and selects an installation of that base with a renderer declaring that pattern and validates
|
|
109
|
+
the supplied config against its schema. Reset requires `baseUi` and removes only that base and pattern's override.
|
|
110
|
+
The unique selection key is `(Space, baseUi, patternId)`; the same pattern can
|
|
111
|
+
have independent overrides in different bases. Uninstall removes the installation, its pinned descriptor and every
|
|
98
112
|
override referencing it in one commit. Reset/uninstall/config edits use local
|
|
99
113
|
pinned metadata; they do not need a live catalog connection.
|
|
100
114
|
|
|
101
|
-
Upgrade keeps the installation ID and all existing overrides.
|
|
115
|
+
Upgrade keeps the installation ID, UI base and all existing overrides. A release
|
|
116
|
+
with another base is rejected before any mutation. Every affected
|
|
102
117
|
renderer must still exist, declare exactly the same pattern/contract ID/version,
|
|
103
118
|
and accept the existing config. A different catalog identity is never silently
|
|
104
119
|
substituted after Space transfer. Any incompatibility rejects the entire write;
|
|
@@ -113,12 +128,15 @@ publication does not assume every MeowLink client supports the same contracts.
|
|
|
113
128
|
|
|
114
129
|
## Deployment and boundaries
|
|
115
130
|
|
|
116
|
-
The cloud service needs a private `
|
|
117
|
-
AWS/OSS provider and
|
|
118
|
-
|
|
119
|
-
access
|
|
120
|
-
|
|
121
|
-
|
|
131
|
+
The cloud service needs a private `ui.customize.cards.storage.bucket` on its configured
|
|
132
|
+
AWS/OSS provider and the platform-wide HTTPS origin `resources.static.base-url` (normally
|
|
133
|
+
`https://static.mhome.ai`, without a path). CloudFront maps its origin to `published/`;
|
|
134
|
+
its S3 access policy must exclude `staging/`. End users receive only bounded, expiring
|
|
135
|
+
create-only staging writes. They receive no published-object overwrite/delete authority.
|
|
136
|
+
This development cutover removes the old binary routes without a compatibility alias.
|
|
137
|
+
Existing development releases/selections containing old delivery URLs require explicit
|
|
138
|
+
recreation; startup and ordinary reads never rewrite or erase them.
|
|
139
|
+
|
|
122
140
|
|
|
123
141
|
Unfinished publishing sessions expire but their draft records and unreferenced
|
|
124
142
|
objects are currently retained. This version provides no automatic garbage
|
|
@@ -136,3 +154,7 @@ a future local execution node. These source capabilities require their matching
|
|
|
136
154
|
published artifacts and deployed services. See the frontend's
|
|
137
155
|
[card guide](../../../../pallas-cat/docs/cards/README.md) for the authoring tools
|
|
138
156
|
and management flow.
|
|
157
|
+
|
|
158
|
+
The UI-base fields are mandatory. There is no legacy-base inference or automatic
|
|
159
|
+
startup conversion. Existing incompatible development documents require explicit
|
|
160
|
+
recreation; ordinary reads and startup must not rewrite them.
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Host provisioning v1
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
Client (desktop/CLI Clientd, Android, iOS). Desktop, Docker
|
|
5
|
-
|
|
3
|
+
BLE-capable embedded Linux Hosts get Wi-Fi or recover an unfinished first claim
|
|
4
|
+
over BLE from a native Client (desktop/CLI Clientd, Android, iOS). Desktop, Docker
|
|
5
|
+
and Android Hosts use LAN discovery rather than advertising BLE setup.
|
|
6
|
+
Provisioning connects the Host to the LAN
|
|
6
7
|
and hands the provisioner a one-time claim token; ownership is then established
|
|
7
8
|
by the existing Host claim over the LAN, which requires that token (section 4).
|
|
8
9
|
|
|
@@ -13,14 +14,16 @@ same characteristic UUID fallback.
|
|
|
13
14
|
|
|
14
15
|
## 1. Advertising
|
|
15
16
|
|
|
16
|
-
-
|
|
17
|
-
|
|
17
|
+
- A BLE-capable Host advertises during first network provisioning, while awaiting
|
|
18
|
+
its first claim (including with a working network), or inside an explicit
|
|
19
|
+
re-provision window. Restart never reopens first-claim authority on an already
|
|
20
|
+
claimed Host.
|
|
18
21
|
- Flags: bit 0 commissionable (set while advertising, except during a code
|
|
19
|
-
lockout), bit 1 set when the Host
|
|
20
|
-
|
|
22
|
+
lockout), bit 1 set when the Host has a saved network, including unclaimed
|
|
23
|
+
recovery and re-provision windows.
|
|
21
24
|
- `shortId`: the first 4 bytes of the SHA-256 of the Host bootstrap public key,
|
|
22
|
-
which
|
|
23
|
-
`fingerprint`); it signs nothing in provisioning or claim.
|
|
25
|
+
which is replaced after factory reset. The bootstrap key only names the Host
|
|
26
|
+
(`shortId`, `fingerprint`); it signs nothing in provisioning or claim.
|
|
24
27
|
- Local name: the Host name, at most 20 bytes.
|
|
25
28
|
|
|
26
29
|
## 2. Pairing code
|
|
@@ -84,18 +87,23 @@ Fallback characteristic UUIDs: the standard endpoints as for pods, `host-info`
|
|
|
84
87
|
`productId` is optional. `onboardingRequired` reports whether this Host still
|
|
85
88
|
awaits its first claim. `networkOnline` reports current LAN readiness. Both
|
|
86
89
|
are optional for older Hosts. A securely paired Host with `networkOnline: true`
|
|
87
|
-
and `onboardingRequired: true` can finish without resubmitting Wi-Fi. `finish`
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
90
|
+
and `onboardingRequired: true` can finish without resubmitting Wi-Fi. `finish`
|
|
91
|
+
issues a fresh first-claim token after checking authoritative Host ownership.
|
|
92
|
+
Already claimed Hosts never issue a new first-claim token.
|
|
93
|
+
- `{"op":"finish"}` → `{"ok":true,"claimToken":"…"}`. After a successful
|
|
94
|
+
first-provisioning join, or secure recovery with an already working network,
|
|
95
|
+
the response carries a claim token: 32 random bytes as 43 unpadded base64url
|
|
96
|
+
characters. A new join persists its token hash before applying Wi-Fi and
|
|
97
|
+
exposes the token only after success. Recovery issues a fresh token after
|
|
98
|
+
checking that the Host is still unclaimed. Repeated `finish` requests in the
|
|
99
|
+
same session return the same token. A claimed Host's re-provision window
|
|
100
|
+
carries no first-claim token.
|
|
101
|
+
`finish` ends the central's setup session. Without it, the Host disconnects the
|
|
102
|
+
central 30 seconds after a successful join; the commissioner retries `finish`
|
|
103
|
+
within that window. Network readiness and mDNS announcement do not establish
|
|
104
|
+
ownership. An unclaimed Host keeps its BLE recovery surface available;
|
|
105
|
+
a claimed Host closes a re-provision window
|
|
106
|
+
after the join.
|
|
99
107
|
|
|
100
108
|
Every request and every encrypted response is at most 512 bytes; the response
|
|
101
109
|
is read with offset reads. `prov-scan` start blocks while the Host scans and
|
|
@@ -157,9 +165,13 @@ Native `host.claim` passes it to `POST /v1/auth/claim`, alongside the environmen
|
|
|
157
165
|
cloud proof and direct Client exchange secret (`core-api::host::access::ClaimRequest`).
|
|
158
166
|
There is no Core-proxied first-claim route. The Host rejects a missing or incorrect
|
|
159
167
|
provisioning token with 403 `HOST_CLAIM_TOKEN_REQUIRED`. The token remains valid
|
|
160
|
-
until claim succeeds
|
|
161
|
-
`completed
|
|
162
|
-
|
|
168
|
+
until claim succeeds, another setup issues a replacement token, or factory reset.
|
|
169
|
+
BLE `completed` confirms the network/handoff step, not Host ownership. The App's
|
|
170
|
+
Host onboarding operation waits for explicit ownership confirmation, then claims
|
|
171
|
+
over the LAN. It completes only after the existing claim API confirms cloud
|
|
172
|
+
registration. It does not install Core or Plugins. Hosts that were not provisioned
|
|
173
|
+
over BLE use the ordinary direct LAN claim flow. See the Foundation Host
|
|
174
|
+
management authorization contract.
|
|
163
175
|
|
|
164
176
|
Error codes are the pod session codes without the credential ones:
|
|
165
177
|
`bluetooth_unavailable`, `device_busy`, `disconnected`, `code_rejected` (retry
|
|
@@ -185,5 +197,6 @@ The schema is `schema/host-provision.v1.schema.json`.
|
|
|
185
197
|
are kept. Closes after a successful join, on `meowhostd provision close`, or
|
|
186
198
|
after 10 minutes.
|
|
187
199
|
- Factory reset: from the local interface (`meowhostd factory-reset`). Stops
|
|
188
|
-
services, forgets saved Wi-Fi
|
|
189
|
-
the bootstrap key, and returns to first provisioning.
|
|
200
|
+
services, forgets saved Wi-Fi on BLE provisioning appliances, erases owners,
|
|
201
|
+
the Host security store and bootstrap key, and returns to first provisioning.
|
|
202
|
+
Machine identity and installed software are retained.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Now attention
|
|
2
|
+
|
|
3
|
+
`/app/now/attention/list` is a Space-read Facade routed by Space execution mode.
|
|
4
|
+
Input is an empty object inside `FacadeCall.input`. Identity comes from the
|
|
5
|
+
verified caller, never an input user ID. Existing Dialog, Twin and reconnect events invalidate the view. Time boundaries
|
|
6
|
+
also refresh it while the page is visible.
|
|
7
|
+
|
|
8
|
+
All eligible items use one score:
|
|
9
|
+
`100 * relation * time * (0.625 * impact + 0.375 * necessity)`.
|
|
10
|
+
There are no source or severity tiers. Personal owner: 1; household: 0.8;
|
|
11
|
+
other personal owner: 0. Round scores to four decimal places, then sort descending
|
|
12
|
+
and by stable ID ascending for ties. The display threshold is 20.
|
|
13
|
+
|
|
14
|
+
Recipients control visibility and are not ownership. Without explicit business
|
|
15
|
+
ownership, shared household facts remain household facts, even if delivered to
|
|
16
|
+
one user. Personal ownership must be declared by the business source.
|
|
17
|
+
|
|
18
|
+
Decay uses the original occurrence time and a configured half-life; retries,
|
|
19
|
+
reads and redelivery must not reset it. Window relevance rises from zero at
|
|
20
|
+
start to one at peak, remains one until deadline, and is zero at deadline.
|
|
21
|
+
Persistent relevance stays one until the underlying condition is cleared.
|
|
22
|
+
Unknown observations do not clear a previously active condition. Expiration of a
|
|
23
|
+
request invalidates that request, but does not resolve a separate device issue.
|
|
24
|
+
|
|
25
|
+
The policy manifest and conformance fixtures are canonical across Rust and Java.
|
|
26
|
+
Unknown reasons and invalid time models have zero score. Policy updates do not
|
|
27
|
+
change business lifecycle state. Ordinary running, recent activity, scheduled
|
|
28
|
+
execution and notification priority alone do not establish attention eligibility.
|
|
29
|
+
|
|
30
|
+
The output contains items, evaluatedAt, nextRefreshAt, policyVersion and
|
|
31
|
+
sourceErrors. Source failures must not be represented as an authoritative empty
|
|
32
|
+
view. Actions continue through their business Facades with fresh permission and
|
|
33
|
+
state checks. Only confirmed completion removes an item; accepting a device
|
|
34
|
+
command is not confirmation that the condition was resolved.
|
|
35
|
+
|
|
36
|
+
Current adapters read pending Dialogs from their authoritative store, applying the
|
|
37
|
+
current audience, expiry and status on each read. Optional `attentionContext`
|
|
38
|
+
can declare `dialog.pending`, `task.userDecision` or `schedule.decisionRequired`.
|
|
39
|
+
Without it, pending Dialogs use household association and a 15-minute half-life.
|
|
40
|
+
Task failure, notification priority and schedule trigger times are not inferred
|
|
41
|
+
as user-decision facts.
|
|
42
|
+
|
|
43
|
+
Standard device facts currently cover `state.water` (`wet` / `dry`) and
|
|
44
|
+
`state.smoke` (`detected` / `clear`). Other readings, including unknown/testing,
|
|
45
|
+
do not create an incident and do not resolve an existing incident. The small
|
|
46
|
+
retained device projection preserves the episode across restarts and Space
|
|
47
|
+
execution-mode migration. Its revision is owned by Attention, independent of
|
|
48
|
+
rebuildable Twin cache counters. Each reconciliation reads current canonical
|
|
49
|
+
Twin state, including retained-history recovery, rather than replaying event
|
|
50
|
+
payloads. Device metadata and retained episodes cover cold/missing caches.
|
|
51
|
+
|
|
52
|
+
All timestamps are epoch milliseconds. `sourceUpdatedAt` is the underlying
|
|
53
|
+
state-change timestamp, not a heartbeat or proof of current connectivity.
|
|
54
|
+
`verificationRequired` marks a retained issue whose current reading is unknown.
|
|
55
|
+
Only one execution owner serves a Space; local and cloud candidates are not
|
|
56
|
+
merged into a second queue. Source errors remain visible alongside usable items.
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"name": "personal",
|
|
4
|
+
"score": 62.5,
|
|
5
|
+
"reasonCode": "dialog.pending",
|
|
6
|
+
"eligible": true,
|
|
7
|
+
"association": {
|
|
8
|
+
"kind": "personal",
|
|
9
|
+
"ownerUserId": "me"
|
|
10
|
+
},
|
|
11
|
+
"userId": "me",
|
|
12
|
+
"time": {
|
|
13
|
+
"mode": "persistent"
|
|
14
|
+
},
|
|
15
|
+
"now": 1000000
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "household",
|
|
19
|
+
"score": 50,
|
|
20
|
+
"reasonCode": "dialog.pending",
|
|
21
|
+
"eligible": true,
|
|
22
|
+
"association": {
|
|
23
|
+
"kind": "household"
|
|
24
|
+
},
|
|
25
|
+
"userId": "me",
|
|
26
|
+
"time": {
|
|
27
|
+
"mode": "persistent"
|
|
28
|
+
},
|
|
29
|
+
"now": 1000000
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"name": "not mine",
|
|
33
|
+
"score": 0,
|
|
34
|
+
"reasonCode": "dialog.pending",
|
|
35
|
+
"eligible": true,
|
|
36
|
+
"association": {
|
|
37
|
+
"kind": "personal",
|
|
38
|
+
"ownerUserId": "me"
|
|
39
|
+
},
|
|
40
|
+
"userId": "other",
|
|
41
|
+
"time": {
|
|
42
|
+
"mode": "persistent"
|
|
43
|
+
},
|
|
44
|
+
"now": 1000000
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"name": "shared screen excludes personal",
|
|
48
|
+
"score": 0,
|
|
49
|
+
"reasonCode": "dialog.pending",
|
|
50
|
+
"eligible": true,
|
|
51
|
+
"association": {
|
|
52
|
+
"kind": "personal",
|
|
53
|
+
"ownerUserId": "me"
|
|
54
|
+
},
|
|
55
|
+
"userId": null,
|
|
56
|
+
"time": {
|
|
57
|
+
"mode": "persistent"
|
|
58
|
+
},
|
|
59
|
+
"now": 1000000
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"name": "ineligible",
|
|
63
|
+
"score": 0,
|
|
64
|
+
"reasonCode": "dialog.pending",
|
|
65
|
+
"eligible": false,
|
|
66
|
+
"association": {
|
|
67
|
+
"kind": "personal",
|
|
68
|
+
"ownerUserId": "me"
|
|
69
|
+
},
|
|
70
|
+
"userId": "me",
|
|
71
|
+
"time": {
|
|
72
|
+
"mode": "persistent"
|
|
73
|
+
},
|
|
74
|
+
"now": 1000000
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"name": "unknown reason",
|
|
78
|
+
"score": 0,
|
|
79
|
+
"reasonCode": "unknown",
|
|
80
|
+
"eligible": true,
|
|
81
|
+
"association": {
|
|
82
|
+
"kind": "personal",
|
|
83
|
+
"ownerUserId": "me"
|
|
84
|
+
},
|
|
85
|
+
"userId": "me",
|
|
86
|
+
"time": {
|
|
87
|
+
"mode": "persistent"
|
|
88
|
+
},
|
|
89
|
+
"now": 1000000
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"name": "half life",
|
|
93
|
+
"score": 31.25,
|
|
94
|
+
"reasonCode": "dialog.pending",
|
|
95
|
+
"eligible": true,
|
|
96
|
+
"association": {
|
|
97
|
+
"kind": "personal",
|
|
98
|
+
"ownerUserId": "me"
|
|
99
|
+
},
|
|
100
|
+
"userId": "me",
|
|
101
|
+
"time": {
|
|
102
|
+
"mode": "decay",
|
|
103
|
+
"occurredAt": 100000,
|
|
104
|
+
"halfLifeMs": 900000
|
|
105
|
+
},
|
|
106
|
+
"now": 1000000
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"name": "one hour",
|
|
110
|
+
"score": 3.9063,
|
|
111
|
+
"reasonCode": "dialog.pending",
|
|
112
|
+
"eligible": true,
|
|
113
|
+
"association": {
|
|
114
|
+
"kind": "personal",
|
|
115
|
+
"ownerUserId": "me"
|
|
116
|
+
},
|
|
117
|
+
"userId": "me",
|
|
118
|
+
"time": {
|
|
119
|
+
"mode": "decay",
|
|
120
|
+
"occurredAt": 100000,
|
|
121
|
+
"halfLifeMs": 900000
|
|
122
|
+
},
|
|
123
|
+
"now": 3700000
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"name": "invalid decay",
|
|
127
|
+
"score": 0,
|
|
128
|
+
"reasonCode": "dialog.pending",
|
|
129
|
+
"eligible": true,
|
|
130
|
+
"association": {
|
|
131
|
+
"kind": "personal",
|
|
132
|
+
"ownerUserId": "me"
|
|
133
|
+
},
|
|
134
|
+
"userId": "me",
|
|
135
|
+
"time": {
|
|
136
|
+
"mode": "decay",
|
|
137
|
+
"occurredAt": 100000,
|
|
138
|
+
"halfLifeMs": 0
|
|
139
|
+
},
|
|
140
|
+
"now": 1000000
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"name": "future creation",
|
|
144
|
+
"score": 0,
|
|
145
|
+
"reasonCode": "dialog.pending",
|
|
146
|
+
"eligible": true,
|
|
147
|
+
"association": {
|
|
148
|
+
"kind": "personal",
|
|
149
|
+
"ownerUserId": "me"
|
|
150
|
+
},
|
|
151
|
+
"userId": "me",
|
|
152
|
+
"time": {
|
|
153
|
+
"mode": "decay",
|
|
154
|
+
"occurredAt": 1000001,
|
|
155
|
+
"halfLifeMs": 900000
|
|
156
|
+
},
|
|
157
|
+
"now": 1000000
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"name": "window before start",
|
|
161
|
+
"score": 0,
|
|
162
|
+
"reasonCode": "dialog.pending",
|
|
163
|
+
"eligible": true,
|
|
164
|
+
"association": {
|
|
165
|
+
"kind": "personal",
|
|
166
|
+
"ownerUserId": "me"
|
|
167
|
+
},
|
|
168
|
+
"userId": "me",
|
|
169
|
+
"time": {
|
|
170
|
+
"mode": "window",
|
|
171
|
+
"start": 100,
|
|
172
|
+
"peak": 200,
|
|
173
|
+
"deadline": 300
|
|
174
|
+
},
|
|
175
|
+
"now": 99
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"name": "window rising",
|
|
179
|
+
"score": 31.25,
|
|
180
|
+
"reasonCode": "dialog.pending",
|
|
181
|
+
"eligible": true,
|
|
182
|
+
"association": {
|
|
183
|
+
"kind": "personal",
|
|
184
|
+
"ownerUserId": "me"
|
|
185
|
+
},
|
|
186
|
+
"userId": "me",
|
|
187
|
+
"time": {
|
|
188
|
+
"mode": "window",
|
|
189
|
+
"start": 100,
|
|
190
|
+
"peak": 200,
|
|
191
|
+
"deadline": 300
|
|
192
|
+
},
|
|
193
|
+
"now": 150
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"name": "window plateau",
|
|
197
|
+
"score": 62.5,
|
|
198
|
+
"reasonCode": "dialog.pending",
|
|
199
|
+
"eligible": true,
|
|
200
|
+
"association": {
|
|
201
|
+
"kind": "personal",
|
|
202
|
+
"ownerUserId": "me"
|
|
203
|
+
},
|
|
204
|
+
"userId": "me",
|
|
205
|
+
"time": {
|
|
206
|
+
"mode": "window",
|
|
207
|
+
"start": 100,
|
|
208
|
+
"peak": 200,
|
|
209
|
+
"deadline": 300
|
|
210
|
+
},
|
|
211
|
+
"now": 299
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"name": "window deadline",
|
|
215
|
+
"score": 0,
|
|
216
|
+
"reasonCode": "dialog.pending",
|
|
217
|
+
"eligible": true,
|
|
218
|
+
"association": {
|
|
219
|
+
"kind": "personal",
|
|
220
|
+
"ownerUserId": "me"
|
|
221
|
+
},
|
|
222
|
+
"userId": "me",
|
|
223
|
+
"time": {
|
|
224
|
+
"mode": "window",
|
|
225
|
+
"start": 100,
|
|
226
|
+
"peak": 200,
|
|
227
|
+
"deadline": 300
|
|
228
|
+
},
|
|
229
|
+
"now": 300
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"name": "invalid window",
|
|
233
|
+
"score": 0,
|
|
234
|
+
"reasonCode": "dialog.pending",
|
|
235
|
+
"eligible": true,
|
|
236
|
+
"association": {
|
|
237
|
+
"kind": "personal",
|
|
238
|
+
"ownerUserId": "me"
|
|
239
|
+
},
|
|
240
|
+
"userId": "me",
|
|
241
|
+
"time": {
|
|
242
|
+
"mode": "window",
|
|
243
|
+
"start": 200,
|
|
244
|
+
"peak": 100,
|
|
245
|
+
"deadline": 300
|
|
246
|
+
},
|
|
247
|
+
"now": 150
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"name": "persistent old hazard",
|
|
251
|
+
"score": 74,
|
|
252
|
+
"reasonCode": "device.waterDetected",
|
|
253
|
+
"eligible": true,
|
|
254
|
+
"association": {
|
|
255
|
+
"kind": "household"
|
|
256
|
+
},
|
|
257
|
+
"userId": "me",
|
|
258
|
+
"time": {
|
|
259
|
+
"mode": "persistent"
|
|
260
|
+
},
|
|
261
|
+
"now": 9000000000000
|
|
262
|
+
}
|
|
263
|
+
]
|