Define explicit scalar input controls
This commit is contained in:
parent
747e29e908
commit
961a5e0df2
8 changed files with 164 additions and 4 deletions
|
|
@ -21,6 +21,14 @@ send changed values through the action's advertised operation; providers own
|
|||
interpretation, persistence, receipts, and simulation. A client must not infer
|
||||
decay or repair a missed release by mutating presented state.
|
||||
|
||||
The `scalar.v1` model exposes an explicit finite numeric control rather than a
|
||||
sampled device axis. `currentValue` is provider-owned state. `minimumValue`,
|
||||
`maximumValue`, and `stepValue` are optional input constraints, and `unit` is an
|
||||
optional semantic label. A client submits the chosen value to `payloadKey`; it
|
||||
does not update `currentValue` optimistically or clamp values beyond the
|
||||
advertised constraints. Providers may leave the range open when the original
|
||||
control accepted arbitrary numeric input.
|
||||
|
||||
The `view-direction.v1` model is a one-shot value sampled when its gesture is
|
||||
performed. The client reads the active semantic view's normalized world-space
|
||||
forward direction and writes X, Y, and Z to the three advertised `payloadKeys`
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
export type InputValue = ({
|
||||
[k: string]: any;
|
||||
} & {
|
||||
model: ("button-hold.v1" | "axis.v1" | "view-direction.v1");
|
||||
model: ("button-hold.v1" | "axis.v1" | "scalar.v1" | "view-direction.v1");
|
||||
payloadKey?: string;
|
||||
currentValue?: number;
|
||||
minimumValue?: number;
|
||||
maximumValue?: number;
|
||||
stepValue?: number;
|
||||
unit?: string;
|
||||
/**
|
||||
* @minItems 3
|
||||
* @maxItems 3
|
||||
|
|
|
|||
|
|
@ -723,12 +723,29 @@ export declare const eveContractSchemas: {
|
|||
readonly required: readonly ["model"];
|
||||
readonly properties: {
|
||||
readonly model: {
|
||||
readonly enum: readonly ["button-hold.v1", "axis.v1", "view-direction.v1"];
|
||||
readonly enum: readonly ["button-hold.v1", "axis.v1", "scalar.v1", "view-direction.v1"];
|
||||
};
|
||||
readonly payloadKey: {
|
||||
readonly type: "string";
|
||||
readonly minLength: 1;
|
||||
};
|
||||
readonly currentValue: {
|
||||
readonly type: "number";
|
||||
};
|
||||
readonly minimumValue: {
|
||||
readonly type: "number";
|
||||
};
|
||||
readonly maximumValue: {
|
||||
readonly type: "number";
|
||||
};
|
||||
readonly stepValue: {
|
||||
readonly type: "number";
|
||||
readonly exclusiveMinimum: 0;
|
||||
};
|
||||
readonly unit: {
|
||||
readonly type: "string";
|
||||
readonly minLength: 1;
|
||||
};
|
||||
readonly payloadKeys: {
|
||||
readonly type: "array";
|
||||
readonly minItems: 3;
|
||||
|
|
@ -755,6 +772,18 @@ export declare const eveContractSchemas: {
|
|||
readonly else: {
|
||||
readonly required: readonly ["payloadKey"];
|
||||
};
|
||||
}, {
|
||||
readonly if: {
|
||||
readonly properties: {
|
||||
readonly model: {
|
||||
readonly const: "scalar.v1";
|
||||
};
|
||||
};
|
||||
readonly required: readonly ["model"];
|
||||
};
|
||||
readonly then: {
|
||||
readonly required: readonly ["currentValue"];
|
||||
};
|
||||
}];
|
||||
readonly additionalProperties: false;
|
||||
};
|
||||
|
|
|
|||
35
packages/eve-contracts/dist/generated/schemas.js
vendored
35
packages/eve-contracts/dist/generated/schemas.js
vendored
|
|
@ -874,6 +874,7 @@ export const eveContractSchemas = {
|
|||
"enum": [
|
||||
"button-hold.v1",
|
||||
"axis.v1",
|
||||
"scalar.v1",
|
||||
"view-direction.v1"
|
||||
]
|
||||
},
|
||||
|
|
@ -881,6 +882,23 @@ export const eveContractSchemas = {
|
|||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"currentValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"minimumValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"maximumValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"stepValue": {
|
||||
"type": "number",
|
||||
"exclusiveMinimum": 0
|
||||
},
|
||||
"unit": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"payloadKeys": {
|
||||
"type": "array",
|
||||
"minItems": 3,
|
||||
|
|
@ -914,6 +932,23 @@ export const eveContractSchemas = {
|
|||
"payloadKey"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"model": {
|
||||
"const": "scalar.v1"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"model"
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"required": [
|
||||
"currentValue"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
|
|
|
|||
|
|
@ -3,8 +3,13 @@
|
|||
export type InputValue = ({
|
||||
[k: string]: any
|
||||
} & {
|
||||
model: ("button-hold.v1" | "axis.v1" | "view-direction.v1")
|
||||
model: ("button-hold.v1" | "axis.v1" | "scalar.v1" | "view-direction.v1")
|
||||
payloadKey?: string
|
||||
currentValue?: number
|
||||
minimumValue?: number
|
||||
maximumValue?: number
|
||||
stepValue?: number
|
||||
unit?: string
|
||||
/**
|
||||
* @minItems 3
|
||||
* @maxItems 3
|
||||
|
|
|
|||
|
|
@ -874,6 +874,7 @@ export const eveContractSchemas = {
|
|||
"enum": [
|
||||
"button-hold.v1",
|
||||
"axis.v1",
|
||||
"scalar.v1",
|
||||
"view-direction.v1"
|
||||
]
|
||||
},
|
||||
|
|
@ -881,6 +882,23 @@ export const eveContractSchemas = {
|
|||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"currentValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"minimumValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"maximumValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"stepValue": {
|
||||
"type": "number",
|
||||
"exclusiveMinimum": 0
|
||||
},
|
||||
"unit": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"payloadKeys": {
|
||||
"type": "array",
|
||||
"minItems": 3,
|
||||
|
|
@ -914,6 +932,23 @@ export const eveContractSchemas = {
|
|||
"payloadKey"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"model": {
|
||||
"const": "scalar.v1"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"model"
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"required": [
|
||||
"currentValue"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
|
|
|
|||
|
|
@ -105,6 +105,30 @@ test("validates scalar and view-direction input value models", () => {
|
|||
inputValue: { model: "button-hold.v1", payloadKey: "active" },
|
||||
}],
|
||||
}).actions[0].inputValue.payloadKey, "active");
|
||||
assert.deepEqual(parseEveInputCapability({
|
||||
...base,
|
||||
actions: [{
|
||||
actionId: "equipment.0.temperature",
|
||||
label: "Target Temperature",
|
||||
operation: "equipment.set-temperature",
|
||||
availability: "available",
|
||||
inputValue: {
|
||||
model: "scalar.v1",
|
||||
payloadKey: "scalarValue",
|
||||
currentValue: 300,
|
||||
minimumValue: 0,
|
||||
stepValue: 1,
|
||||
unit: "kelvin",
|
||||
},
|
||||
}],
|
||||
}).actions[0].inputValue, {
|
||||
model: "scalar.v1",
|
||||
payloadKey: "scalarValue",
|
||||
currentValue: 300,
|
||||
minimumValue: 0,
|
||||
stepValue: 1,
|
||||
unit: "kelvin",
|
||||
});
|
||||
assert.deepEqual(parseEveInputCapability({
|
||||
...base,
|
||||
actions: [{
|
||||
|
|
@ -128,6 +152,16 @@ test("validates scalar and view-direction input value models", () => {
|
|||
inputValue: { model: "view-direction.v1", payloadKey: "directionX" },
|
||||
}],
|
||||
}), EveContractValidationError);
|
||||
assert.throws(() => parseEveInputCapability({
|
||||
...base,
|
||||
actions: [{
|
||||
actionId: "equipment.0.temperature",
|
||||
label: "Target Temperature",
|
||||
operation: "equipment.set-temperature",
|
||||
availability: "available",
|
||||
inputValue: { model: "scalar.v1", payloadKey: "scalarValue" },
|
||||
}],
|
||||
}), EveContractValidationError);
|
||||
});
|
||||
|
||||
test("validates an existing canonical Eve surface fixture", async () => {
|
||||
|
|
|
|||
|
|
@ -48,8 +48,13 @@
|
|||
"type": "object",
|
||||
"required": ["model"],
|
||||
"properties": {
|
||||
"model": { "enum": ["button-hold.v1", "axis.v1", "view-direction.v1"] },
|
||||
"model": { "enum": ["button-hold.v1", "axis.v1", "scalar.v1", "view-direction.v1"] },
|
||||
"payloadKey": { "type": "string", "minLength": 1 },
|
||||
"currentValue": { "type": "number" },
|
||||
"minimumValue": { "type": "number" },
|
||||
"maximumValue": { "type": "number" },
|
||||
"stepValue": { "type": "number", "exclusiveMinimum": 0 },
|
||||
"unit": { "type": "string", "minLength": 1 },
|
||||
"payloadKeys": {
|
||||
"type": "array",
|
||||
"minItems": 3,
|
||||
|
|
@ -63,6 +68,10 @@
|
|||
"if": { "properties": { "model": { "const": "view-direction.v1" } }, "required": ["model"] },
|
||||
"then": { "required": ["payloadKeys"] },
|
||||
"else": { "required": ["payloadKey"] }
|
||||
},
|
||||
{
|
||||
"if": { "properties": { "model": { "const": "scalar.v1" } }, "required": ["model"] },
|
||||
"then": { "required": ["currentValue"] }
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
|
|
|
|||
Loading…
Reference in a new issue