mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
test: close device presentation review findings
Issue: #267 User-Visible: no
This commit is contained in:
File diff suppressed because one or more lines are too long
Vendored
+27
-27
File diff suppressed because one or more lines are too long
@@ -27,9 +27,9 @@ mutation evidence в одном pull request.
|
||||
| L01 | `marker.removed:true` | `pre.lifecycle.removed` | marker отсутствует в roster/DOM | отсутствует | `devices` tombstone test; `presentation-row-contract` |
|
||||
| L02 | HA-disabled, View/киоск/static | `lifecycle.ha_disabled_hidden` | face скрыт, live state не участвует | отсутствует на View | `device-presentation-policy-lifecycle`; `presentation-row-contract` |
|
||||
| L03 | HA-disabled, Device editor | `lifecycle.ha_disabled_hidden` | служебный ghost/preview с причиной `ha_disabled`, без live face | editor-owned, без service action | `device-presentation-policy-lifecycle`; `presentation-row-contract` |
|
||||
| L04 | user-hidden, View/киоск/static | `lifecycle.user_hidden` | marker и hit-area скрыты | отсутствует | `device-presentation-policy-lifecycle`; `presentation-row-contract` |
|
||||
| L05 | user-hidden, design preview | `lifecycle.user_hidden_preview` | сохранённый дизайн видим; notice `hidden_design_preview` | preview inert | `device-presentation-policy-lifecycle`; `presentation-row-contract` |
|
||||
| L06 | orphaned/unverified | `lifecycle.orphaned_diagnostic` / `lifecycle.unverified_diagnostic` | нейтральная диагностическая проекция с причиной, pulse/service не оживают | surface-owned safe path | `device-presentation-policy-lifecycle`; `presentation-row-contract` |
|
||||
| L04 | user-hidden, View/киоск/static | `lifecycle.user_hidden` | marker и hit-area скрыты | отсутствует | `device-presentation-policy-user-hidden`; `presentation-row-contract` |
|
||||
| L05 | user-hidden, design preview | `lifecycle.user_hidden_preview` | сохранённый дизайн видим; notice `hidden_design_preview` | preview inert | `device-presentation-policy-user-hidden-preview`; `presentation-row-contract` |
|
||||
| L06 | orphaned binding | `lifecycle.orphaned_diagnostic` | нейтральная диагностическая проекция с причиной, pulse/service не оживают | surface-owned safe path | `device-presentation-policy-orphaned`; `presentation-row-contract` |
|
||||
|
||||
## Источник лица и доступность
|
||||
|
||||
@@ -48,6 +48,7 @@ mutation evidence в одном pull request.
|
||||
| S11 | registry role временно отсутствует, есть primary | `source.primary_fallback` | deterministic primary fallback | normal | `presentation-source-decision-trace`; `presentation-row-contract` |
|
||||
| S12 | пригодного source нет | `source.none` | neutral base-icon fallback | normal | `presentation-source-decision-trace`; `presentation-row-contract` |
|
||||
| S13 | critical alarm sibling вне обычного source | `source.critical_sibling` + `status.alarm` | alarm добавлен в aggregate и побеждает normal status | normal | `device-presentation-policy-alarm`; `presentation-row-contract` |
|
||||
| S14 | static plan fast path без source details | `source.skipped_static_fast_path` | source graph намеренно не вычисляется; static face остаётся neutral | normal; без source-derived данных | `presentation-static-source-fast-path`; `presentation-row-contract` |
|
||||
|
||||
## Финальное лицо, контент и диагностика
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"version": 1,
|
||||
"fixture": "synthetic-only",
|
||||
"chromium": "151.0.7922.34",
|
||||
"sourceFingerprint": "fb7f3cbc180b24cb91421c5cd0b8808cd4e2d0c38dd0c6f00f46d59f94e4a6d7",
|
||||
"sourceFingerprint": "bbdc8981e3d11029702a3e5b78a9026e6814bb2bdf8e3cb56d0c2e8f7c519b2c",
|
||||
"captureScriptSha256": "ce2e9542fed9dade3085be87d16f69adb2ac8262893ad78ad966b1b9673f2983",
|
||||
"command": "npm run build && node demo/docs/capture.mjs",
|
||||
"scenarios": {
|
||||
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "fb7f3cbc180b24cb91421c5cd0b8808cd4e2d0c38dd0c6f00f46d59f94e4a6d7",
|
||||
"sourceSha256": "bbdc8981e3d11029702a3e5b78a9026e6814bb2bdf8e3cb56d0c2e8f7c519b2c",
|
||||
"imageSha256": "36223106c073f07d8cc3ecf8eaab37192ebb2687daba65c5c21047d0b7890de0"
|
||||
},
|
||||
"view-touch": {
|
||||
@@ -25,7 +25,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "fb7f3cbc180b24cb91421c5cd0b8808cd4e2d0c38dd0c6f00f46d59f94e4a6d7",
|
||||
"sourceSha256": "bbdc8981e3d11029702a3e5b78a9026e6814bb2bdf8e3cb56d0c2e8f7c519b2c",
|
||||
"imageSha256": "41e3ba67f8db0e98f26f484293af83ef937c369ca5ca6a59a3350d8954c906f4"
|
||||
},
|
||||
"space-create": {
|
||||
@@ -36,7 +36,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "fb7f3cbc180b24cb91421c5cd0b8808cd4e2d0c38dd0c6f00f46d59f94e4a6d7",
|
||||
"sourceSha256": "bbdc8981e3d11029702a3e5b78a9026e6814bb2bdf8e3cb56d0c2e8f7c519b2c",
|
||||
"imageSha256": "0dc024726327f60f4a9ceaf3044381691f81f1090af81d1812e870f22d9343ba"
|
||||
},
|
||||
"room-contour-close": {
|
||||
@@ -47,7 +47,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "fb7f3cbc180b24cb91421c5cd0b8808cd4e2d0c38dd0c6f00f46d59f94e4a6d7",
|
||||
"sourceSha256": "bbdc8981e3d11029702a3e5b78a9026e6814bb2bdf8e3cb56d0c2e8f7c519b2c",
|
||||
"imageSha256": "44cfaa95bd51e2cd628400e28db0ad8b2f0cd904385845bd402494f3f5c0d93c"
|
||||
},
|
||||
"plan-context-tray": {
|
||||
@@ -58,7 +58,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "fb7f3cbc180b24cb91421c5cd0b8808cd4e2d0c38dd0c6f00f46d59f94e4a6d7",
|
||||
"sourceSha256": "bbdc8981e3d11029702a3e5b78a9026e6814bb2bdf8e3cb56d0c2e8f7c519b2c",
|
||||
"imageSha256": "e0662429b423fb74151b583dcc2c8635b001b637d03bbf7a6b16aec46399c3f8"
|
||||
},
|
||||
"device-editor": {
|
||||
@@ -69,7 +69,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "fb7f3cbc180b24cb91421c5cd0b8808cd4e2d0c38dd0c6f00f46d59f94e4a6d7",
|
||||
"sourceSha256": "bbdc8981e3d11029702a3e5b78a9026e6814bb2bdf8e3cb56d0c2e8f7c519b2c",
|
||||
"imageSha256": "d0ffd31ce80bfde21ab75da356a5fc1af38246f2b301030880320620c228d89d"
|
||||
},
|
||||
"device-display-preview": {
|
||||
@@ -80,7 +80,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "fb7f3cbc180b24cb91421c5cd0b8808cd4e2d0c38dd0c6f00f46d59f94e4a6d7",
|
||||
"sourceSha256": "bbdc8981e3d11029702a3e5b78a9026e6814bb2bdf8e3cb56d0c2e8f7c519b2c",
|
||||
"imageSha256": "2cdabae1f89c3286e4fac0ce30f757ee1690b707ab8a5488748b7cd420626160"
|
||||
},
|
||||
"background-editor": {
|
||||
@@ -91,7 +91,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "fb7f3cbc180b24cb91421c5cd0b8808cd4e2d0c38dd0c6f00f46d59f94e4a6d7",
|
||||
"sourceSha256": "bbdc8981e3d11029702a3e5b78a9026e6814bb2bdf8e3cb56d0c2e8f7c519b2c",
|
||||
"imageSha256": "30147bb00a90eea7136b4cee30995f6e6a9217b5132f3e8d3ad7471413b1af8a"
|
||||
},
|
||||
"room-card": {
|
||||
@@ -102,7 +102,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "fb7f3cbc180b24cb91421c5cd0b8808cd4e2d0c38dd0c6f00f46d59f94e4a6d7",
|
||||
"sourceSha256": "bbdc8981e3d11029702a3e5b78a9026e6814bb2bdf8e3cb56d0c2e8f7c519b2c",
|
||||
"imageSha256": "029a3e69ec647a8a370d99e6bb7f9225833c526739076022f6b52ba54bff30ea"
|
||||
},
|
||||
"device-info": {
|
||||
@@ -113,7 +113,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "fb7f3cbc180b24cb91421c5cd0b8808cd4e2d0c38dd0c6f00f46d59f94e4a6d7",
|
||||
"sourceSha256": "bbdc8981e3d11029702a3e5b78a9026e6814bb2bdf8e3cb56d0c2e8f7c519b2c",
|
||||
"imageSha256": "dd492f53150b7149085daada5cce9eeae9bde9e7ea1d86679a54b3041f72f517"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
| L03 | HA-disabled в служебном Device editor | диагностический marker/preview с причиной, без live state/action |
|
||||
| L04 | user-hidden в View/киоске/static card | marker и hit-area отсутствуют |
|
||||
| L05 | user-hidden в design preview | реальный сохранённый дизайн видим, notice `hidden_design_preview`, preview inert |
|
||||
| L06 | orphaned/unverified binding | сохраняется действующая диагностическая проекция и причина; pulse/service не оживают |
|
||||
| L06 | orphaned binding | сохраняется действующая диагностическая проекция и причина; pulse/service не оживают |
|
||||
|
||||
### 6.2 Source / availability
|
||||
|
||||
@@ -154,6 +154,7 @@
|
||||
| S11 | registry role временно отсутствует, есть live primary | deterministic `primary` fallback без смены сохранённого binding |
|
||||
| S12 | нет пригодного source | neutral icon fallback; не выбирается случайная sibling entity |
|
||||
| S13 | critical alarm sibling вне обычного face source | alarm добавляется к semantic aggregate и имеет публичный приоритет |
|
||||
| S14 | static plan fast path с `sourceDetails:false` | source graph не вычисляется; trace явно фиксирует пропуск, static face остаётся neutral |
|
||||
|
||||
### 6.3 Face / content / diagnostics
|
||||
|
||||
@@ -209,7 +210,7 @@ semantic facts, не читает HA registry/state и не строит light g
|
||||
|
||||
```ts
|
||||
interface DevicePresentationPolicyInput {
|
||||
bindingLifecycle: 'active' | 'ha_disabled' | 'orphaned' | 'unverified';
|
||||
bindingLifecycle: 'active' | 'ha_disabled' | 'orphaned';
|
||||
userHidden: boolean;
|
||||
designPreview: boolean;
|
||||
display: DeviceDisplayMode;
|
||||
@@ -250,7 +251,7 @@ Production decision IDs описывают **правила**, а не test fixt
|
||||
- `device-toggle.ts` и surface handlers владеют action/security/interactivity;
|
||||
- `resolvePresentationSources()` продолжает владеть HA/light graph, но
|
||||
возвращает дополнительно явный source-decision ID либо эквивалентный trace,
|
||||
чтобы S01…S13 не зависели от чтения порядка `if`;
|
||||
чтобы S01…S14 не зависели от чтения порядка `if`;
|
||||
- `houseplan-card.ts`, `space-card.ts`, `space-render.ts` не получают права
|
||||
переопределять policy result.
|
||||
|
||||
@@ -409,7 +410,7 @@ renderer и surfaces не принимают альтернативных реш
|
||||
### AC3 — source decisions названы
|
||||
|
||||
Каждая ветка `cover|controls|light|device_role|primary|none` и critical sibling
|
||||
возвращает стабильный decision ID/trace; S01…S13 проверяют наблюдаемый output.
|
||||
возвращает стабильный decision ID/trace; S01…S14 проверяют наблюдаемый output.
|
||||
|
||||
**Доказательство:** parameterized unit.
|
||||
|
||||
@@ -545,4 +546,3 @@ node scripts/mutation-gate.mjs --id=<каждый новый/изменённы
|
||||
является самоцелью.
|
||||
5. Existing browser smoke расширяется только если это остаётся узким сценарием;
|
||||
иначе создаётся новый `smoke_device_presentation_matrix.mjs`.
|
||||
|
||||
|
||||
@@ -2146,14 +2146,70 @@ export const MUTANTS = [
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
|
||||
+ '&& node --test --test-name-pattern="every documented decision row" '
|
||||
+ 'test/device-presentation-policy.test.mjs',
|
||||
because: 'HA-disabled and user-hidden markers must not leak live faces back into View; '
|
||||
+ 'the pure policy test exercises both hidden output and the explicit design-preview exception',
|
||||
because: 'HA-disabled markers must not leak live faces back into View or the device editor; '
|
||||
+ 'the pure policy test exercises the shared lifecycle gate on both surfaces',
|
||||
patches: [{
|
||||
file: 'src/device-presentation-policy.ts',
|
||||
find: " if (input.bindingLifecycle === 'ha_disabled') {\n effectiveHidden = true;",
|
||||
replace: " if (input.bindingLifecycle === 'ha_disabled') {\n effectiveHidden = false;",
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'device-presentation-policy-user-hidden',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
|
||||
+ '&& node --test --test-name-pattern="every documented decision row" '
|
||||
+ 'test/device-presentation-policy.test.mjs',
|
||||
because: 'a user-hidden marker must stay out of View while the separate design-preview '
|
||||
+ 'exception remains explicit and independently protected',
|
||||
patches: [{
|
||||
file: 'src/device-presentation-policy.ts',
|
||||
find: ' } else if (input.userHidden && !input.designPreview) {\n'
|
||||
+ ' effectiveHidden = true;',
|
||||
replace: ' } else if (input.userHidden && !input.designPreview) {\n'
|
||||
+ ' effectiveHidden = false;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'device-presentation-policy-user-hidden-preview',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
|
||||
+ '&& node --test --test-name-pattern="every documented decision row" '
|
||||
+ 'test/device-presentation-policy.test.mjs',
|
||||
because: 'design preview must keep the saved face of a user-hidden marker instead of '
|
||||
+ 'collapsing it into the ordinary active lifecycle',
|
||||
patches: [{
|
||||
file: 'src/device-presentation-policy.ts',
|
||||
find: " } else if (input.userHidden) {\n decisions.push('lifecycle.user_hidden_preview');",
|
||||
replace: " } else if (false && input.userHidden) {\n decisions.push('lifecycle.user_hidden_preview');",
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'device-presentation-policy-orphaned',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
|
||||
+ '&& node --test --test-name-pattern="every documented decision row" '
|
||||
+ 'test/device-presentation-policy.test.mjs',
|
||||
because: 'an orphaned saved binding must retain its diagnostic lifecycle decision and '
|
||||
+ 'must not be treated as an ordinary active marker',
|
||||
patches: [{
|
||||
file: 'src/device-presentation-policy.ts',
|
||||
find: " } else if (input.bindingLifecycle === 'orphaned') {\n"
|
||||
+ " decisions.push('lifecycle.orphaned_diagnostic');",
|
||||
replace: " } else if (false && input.bindingLifecycle === 'orphaned') {\n"
|
||||
+ " decisions.push('lifecycle.orphaned_diagnostic');",
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'presentation-static-source-fast-path',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
|
||||
+ '&& node --test --test-name-pattern="every documented decision row" '
|
||||
+ 'test/device-presentation-policy.test.mjs',
|
||||
because: 'the static plan fast path deliberately skips source discovery and must expose '
|
||||
+ 'that bounded decision instead of silently looking like an evaluated empty graph',
|
||||
patches: [{
|
||||
file: 'src/device-presentation.ts',
|
||||
find: " sourceKind: 'none', decisionIds: ['source.skipped_static_fast_path'],",
|
||||
replace: " sourceKind: 'none', decisionIds: ['source.none'],",
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'device-presentation-policy-static',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
|
||||
|
||||
@@ -27,7 +27,7 @@ export type PresentationReason =
|
||||
| 'orphaned';
|
||||
|
||||
export type BindingPresentationLifecycle =
|
||||
| 'active' | 'ha_disabled' | 'orphaned' | 'unverified';
|
||||
| 'active' | 'ha_disabled' | 'orphaned';
|
||||
|
||||
export type PresentationFace = 'icon' | 'value';
|
||||
export type ValueFallbackReason =
|
||||
@@ -77,8 +77,7 @@ export function resolveDevicePresentationPolicy(
|
||||
): DevicePresentationPolicyResult {
|
||||
const decisions: string[] = [];
|
||||
const bindingUnavailable = input.bindingLifecycle === 'ha_disabled'
|
||||
|| input.bindingLifecycle === 'orphaned'
|
||||
|| input.bindingLifecycle === 'unverified';
|
||||
|| input.bindingLifecycle === 'orphaned';
|
||||
|
||||
let effectiveHidden = false;
|
||||
if (input.bindingLifecycle === 'ha_disabled') {
|
||||
@@ -91,8 +90,6 @@ export function resolveDevicePresentationPolicy(
|
||||
decisions.push('lifecycle.user_hidden_preview');
|
||||
} else if (input.bindingLifecycle === 'orphaned') {
|
||||
decisions.push('lifecycle.orphaned_diagnostic');
|
||||
} else if (input.bindingLifecycle === 'unverified') {
|
||||
decisions.push('lifecycle.unverified_diagnostic');
|
||||
} else {
|
||||
decisions.push('lifecycle.active');
|
||||
}
|
||||
|
||||
@@ -585,7 +585,7 @@ export function resolveDevicePresentation(
|
||||
const haDisabled = status?.kind === 'ha_disabled';
|
||||
const orphaned = status?.kind === 'orphaned';
|
||||
const lifecycle: BindingPresentationLifecycle = haDisabled ? 'ha_disabled'
|
||||
: orphaned ? 'orphaned' : status?.kind === 'unverified' ? 'unverified' : 'active';
|
||||
: orphaned ? 'orphaned' : 'active';
|
||||
const userHidden = d.userHidden === true || d.marker?.hidden === true;
|
||||
const combined = combineVisualSamples(sources.samples);
|
||||
const lockSource = sources.visualSources.find((source) => source.eid.startsWith('lock.'));
|
||||
|
||||
@@ -135,10 +135,7 @@ const rowRunners = {
|
||||
}),
|
||||
L06: () => {
|
||||
const orphaned = resolveDevicePresentationPolicy(basePolicy({ bindingLifecycle: 'orphaned' }));
|
||||
const unverified = resolveDevicePresentationPolicy(basePolicy({ bindingLifecycle: 'unverified' }));
|
||||
assert.equal(orphaned.bindingUnavailable, true);
|
||||
assert.equal(unverified.bindingUnavailable, true);
|
||||
assertDecision(unverified, 'lifecycle.unverified_diagnostic');
|
||||
return orphaned;
|
||||
},
|
||||
S01: sourceRow({ entities: ['cover.main'], primary: 'cover.main', tapAction: 'info' },
|
||||
@@ -205,6 +202,12 @@ const rowRunners = {
|
||||
assert.equal(r.visual.status, 'alarm');
|
||||
assert.equal(r.criticalSources[0].eid, 'binary_sensor.smoke');
|
||||
}),
|
||||
S14: presentationRow({
|
||||
marker: { id: 'd1', binding: 'device:d1', display: 'static_icon' },
|
||||
}, { sourceDetails: false }, (r) => {
|
||||
assert.equal(r.sourceKind, 'none');
|
||||
assert.deepEqual(r.visual, neutral);
|
||||
}),
|
||||
F01: policyRow({
|
||||
sourceVisual: { availability: 'available', status: 'alarm', activity: 'none' },
|
||||
}, (r) => assert.equal(r.visual.status, 'alarm')),
|
||||
@@ -399,11 +402,6 @@ test('device presentation decision table rows exercise lifecycle and ordered pol
|
||||
const orphaned = resolveDevicePresentationPolicy(basePolicy({ bindingLifecycle: 'orphaned' }));
|
||||
assertDecision(orphaned, 'lifecycle.orphaned_diagnostic');
|
||||
assert.equal(orphaned.bindingUnavailable, true);
|
||||
const unverified = resolveDevicePresentationPolicy(basePolicy({ bindingLifecycle: 'unverified' }));
|
||||
assertDecision(unverified, 'lifecycle.unverified_diagnostic');
|
||||
assert.equal(unverified.bindingUnavailable, true);
|
||||
assert.equal(unverified.pulseEligible, false);
|
||||
|
||||
const staticFace = resolveDevicePresentationPolicy(basePolicy({
|
||||
display: 'static_icon', valueAvailable: true, vacuumLiveRequested: true,
|
||||
sourceVisual: { availability: 'available', status: 'alarm', activity: 'running' },
|
||||
|
||||
+4
-3
@@ -8,9 +8,9 @@ const ROWS = [
|
||||
['L01', 'pre.lifecycle.removed', 'presentation-row-contract'],
|
||||
['L02', 'lifecycle.ha_disabled_hidden', 'device-presentation-policy-lifecycle'],
|
||||
['L03', 'lifecycle.ha_disabled_hidden', 'device-presentation-policy-lifecycle'],
|
||||
['L04', 'lifecycle.user_hidden', 'device-presentation-policy-lifecycle'],
|
||||
['L05', 'lifecycle.user_hidden_preview', 'device-presentation-policy-lifecycle'],
|
||||
['L06', 'lifecycle.orphaned_diagnostic', 'device-presentation-policy-lifecycle'],
|
||||
['L04', 'lifecycle.user_hidden', 'device-presentation-policy-user-hidden'],
|
||||
['L05', 'lifecycle.user_hidden_preview', 'device-presentation-policy-user-hidden-preview'],
|
||||
['L06', 'lifecycle.orphaned_diagnostic', 'device-presentation-policy-orphaned'],
|
||||
['S01', 'source.cover', 'presentation-source-decision-trace'],
|
||||
['S02', 'source.cover_capability_bypassed', 'presentation-source-decision-trace'],
|
||||
['S03', 'source.controls', 'controller-availability-follows-target'],
|
||||
@@ -24,6 +24,7 @@ const ROWS = [
|
||||
['S11', 'source.primary_fallback', 'presentation-source-decision-trace'],
|
||||
['S12', 'source.none', 'presentation-source-decision-trace'],
|
||||
['S13', 'source.critical_sibling', 'device-presentation-policy-alarm'],
|
||||
['S14', 'source.skipped_static_fast_path', 'presentation-static-source-fast-path'],
|
||||
['F01', 'status.alarm', 'device-presentation-policy-alarm'],
|
||||
['F02', 'status.unavailable', 'device-presentation-policy-unavailable'],
|
||||
['F03', 'source.device_role', 'presentation-source-decision-trace'],
|
||||
|
||||
Reference in New Issue
Block a user