Skip to main content
Glama

Validate series

validate_series
Read-onlyIdempotent

Runs a run_trajectory request (without a readout) and compares one published quantity with the agent's measurements, each at a landed step. The answer is the error in numbers (rms, mean signed, greatest absolute, model minus measurement, each with its exact hex), the model value at every compared step in decimals (model_values) and exact (model_values_hex), and a hash of the measurements, under one seal. It sets no threshold: the numbers are the answer. The seal has no key, so it does not show who measured or who computed. commitment, optional, opens a salted SHA-384 the measurements were locked with before the comparison: data that are not the committed ones are refused before computing (CommitmentDoesNotMatch), and the seal covers it. genesis_seal verify-validation rebuilds the seal, the statistics and the commitment from the answer alone. In place of run, solves takes a plan of solves as run_dataset takes it (solver and plan, at most 64 solves), each measurement at a row of the plan: the solves are sealed under one dataset_seal, and the comparison by the same rules with the dataset_seal in the place of the run seal and the row in the place of the step; a measured row whose solve did not converge is counted in not_reached. The same request sent again gives the same seal. On this open connection a plan of solves holds the engine's own 64 and at most 15 s of them, or one, at each solver's measured time, which describe_solver states with the count (OPEN_PLAN_SECONDS). One address holds at most 1 physics permit at a time, and long work (a solve, a plan of runs or of solves, a run of more than 10000 steps, or a verification that computes one again) runs 1 at a time. A call that finds no permit or no place is answered "Too many concurrent physics tasks." and nothing waits: the same call sent later is answered once one is free. An answer is waited for 60 seconds, and long work is stopped there.

Input Schema

NameRequiredDescriptionDefault
runNoOne anchored run. Total steps must be <= 1000000. Recorded frames must be <= 10000. The shape of initial and of each segment's load depends on the pair: describe_card gives it.
solvesNoIn place of run: a plan of solves as run_dataset takes it (solver and plan, a list or a grid, at most 64 solves). quantity is then one number the solver publishes in its result, and each measurement names a row of the plan, numbered from 0, in place of a step.
quantityYesThe name of one number the card publishes in its state, a plain name that has a '_hex' sibling in the state. A flag is refused.
componentNo0, 1 or 2: which of the three components of a 3-vector quantity is compared. Required when the quantity is a 3-vector, and refused when it is not. Any other value is refused.
commitmentNoOptional: a commitment the measurements were locked with before this comparison, opened by this request. sha384 is the SHA-384 of these bytes: the line zero-trust-physics/measurement-commitment/v2 and a line break; the sealed form (the text a request's seal is taken over: keys sorted by their bytes, each number x and the 16 hex digits of its 64-bit float, no spaces) of {"component": <this request's component, or null>, "measurements": <this request's measurements>, "quantity": <this request's quantity>}; a line break; and the salt's bytes, its hex decoded. salt is 32 to 128 lowercase hex digits, 16 to 64 bytes, kept back until the comparison so that the data are not found from the sha384 by trying values. The engine makes the digest again from the request before computing: data that do not open it (a value, a step or a row changed, moved, added or dropped, another quantity or another salt) are refused as CommitmentDoesNotMatch, a salt shorter than 16 bytes as CommitmentSaltTooShort, a field of the wrong form as CommitmentMalformed, and sha384 or salt left out as InputMissing; nothing is computed and nothing is sealed. Opened, the comparison runs as it runs without one, validation_seal takes the commitment as a sixth part, and the answer says so in commitment_opened. A commitment shows that the data were not changed after it was made; when it was made is shown by where its sha384 was published before the comparison.
measurementsYesAt most 10000. A measurement is compared with the state after landed step k. There is no interpolation and no time matching: a measurement is placed by its step, its time since the start divided by dt_s.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed5 schema fields changed
    • changedInput schema / properties / commitment / description
      Previous value: -"Optional: a commitment the measurements were locked with before this comparison, opened by this request. sha256 is the SHA-256 of these bytes: the line zero-trust-physics/measurement-commitment/v1 and a line break; the sealed form (the text a request's seal is taken over: keys sorted by their bytes, each number x and the 16 hex digits of its 64-bit float, no spaces) of {\"component\": <this request's component, or null>, \"measurements\": <this request's measurements>, \"quantity\": <this request's quantity>}; a line break; and the salt's bytes, its hex decoded. salt is 32 to 128 lowercase hex digits, 16 to 64 bytes, kept back until the comparison so that the data are not found from the sha256 by trying values. The engine makes the digest again from the request before computing: data that do not open it (a value, a step or a row changed, moved, added or dropped, another quantity or another salt) are refused as CommitmentDoesNotMatch, a salt shorter than 16 bytes as CommitmentSaltTooShort, a field of the wrong form as CommitmentMalformed, and sha256 or salt left out as InputMissing; nothing is computed and nothing is sealed. Opened, the comparison runs as it runs without one, validation_seal takes the commitment as a sixth part, and the answer says so in commitment_opened. A commitment shows that the data were not changed after it was made; when it was made is shown by where its sha256 was published before the comparison."New value: +"Optional: a commitment the measurements were locked with before this comparison, opened by this request. sha384 is the SHA-384 of these bytes: the line zero-trust-physics/measurement-commitment/v2 and a line break; the sealed form (the text a request's seal is taken over: keys sorted by their bytes, each number x and the 16 hex digits of its 64-bit float, no spaces) of {\"component\": <this request's component, or null>, \"measurements\": <this request's measurements>, \"quantity\": <this request's quantity>}; a line break; and the salt's bytes, its hex decoded. salt is 32 to 128 lowercase hex digits, 16 to 64 bytes, kept back until the comparison so that the data are not found from the sha384 by trying values. The engine makes the digest again from the request before computing: data that do not open it (a value, a step or a row changed, moved, added or dropped, another quantity or another salt) are refused as CommitmentDoesNotMatch, a salt shorter than 16 bytes as CommitmentSaltTooShort, a field of the wrong form as CommitmentMalformed, and sha384 or salt left out as InputMissing; nothing is computed and nothing is sealed. Opened, the comparison runs as it runs without one, validation_seal takes the commitment as a sixth part, and the answer says so in commitment_opened. A commitment shows that the data were not changed after it was made; when it was made is shown by where its sha384 was published before the comparison."
    • changedInput schema / properties / commitment / properties / salt / description
      Previous value: -"The salt the sha256 was made with: 32 to 128 lowercase hex digits, 16 to 64 bytes."New value: +"The salt the sha384 was made with: 32 to 128 lowercase hex digits, 16 to 64 bytes."
    • removedInput schema / properties / commitment / properties / sha256
      Removed value: -{
      -  "description": "The SHA-256 committed, 64 lowercase hex digits.",
      -  "pattern": "^[0-9a-f]{64}$",
      -  "type": "string"
      -}
    • addedInput schema / properties / commitment / properties / sha384
      Added value: +{
      +  "description": "The SHA-384 committed, 96 lowercase hex digits.",
      +  "pattern": "^[0-9a-f]{96}$",
      +  "type": "string"
      +}
    • changedInput schema / properties / commitment / required
      Previous value: -[
      -  "sha256",
      -  "salt"
      -]New value: +[
      +  "sha384",
      +  "salt"
      +]
  2. Changed1 schema field changed
    • changedInput schema / description
      Previous value: -"One run, or one plan of solves, and measurements of one quantity. The answer is the error in numbers, sealed with a hash of the measurements. It holds no verdict. A request holds run or solves, not both."New value: +"One run, or one plan of solves, and measurements of one quantity. The answer is the error in numbers, sealed with a hash of the measurements. It sets no threshold. A request holds run or solves, not both."
  3. Changed1 schema field changed
    • addedInput schema / properties / commitment
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "Optional: a commitment the measurements were locked with before this comparison, opened by this request. sha256 is the SHA-256 of these bytes: the line zero-trust-physics/measurement-commitment/v1 and a line break; the sealed form (the text a request's seal is taken over: keys sorted by their bytes, each number x and the 16 hex digits of its 64-bit float, no spaces) of {\"component\": <this request's component, or null>, \"measurements\": <this request's measurements>, \"quantity\": <this request's quantity>}; a line break; and the salt's bytes, its hex decoded. salt is 32 to 128 lowercase hex digits, 16 to 64 bytes, kept back until the comparison so that the data are not found from the sha256 by trying values. The engine makes the digest again from the request before computing: data that do not open it (a value, a step or a row changed, moved, added or dropped, another quantity or another salt) are refused as CommitmentDoesNotMatch, a salt shorter than 16 bytes as CommitmentSaltTooShort, a field of the wrong form as CommitmentMalformed, and sha256 or salt left out as InputMissing; nothing is computed and nothing is sealed. Opened, the comparison runs as it runs without one, validation_seal takes the commitment as a sixth part, and the answer says so in commitment_opened. A commitment shows that the data were not changed after it was made; when it was made is shown by where its sha256 was published before the comparison.",
      +  "properties": {
      +    "salt": {
      +      "description": "The salt the sha256 was made with: 32 to 128 lowercase hex digits, 16 to 64 bytes.",
      +      "type": "string"
      +    },
      +    "sha256": {
      +      "description": "The SHA-256 committed, 64 lowercase hex digits.",
      +      "pattern": "^[0-9a-f]{64}$",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "sha256",
      +    "salt"
      +  ],
      +  "type": "object"
      +}
  4. Changed3 schema fields changed
    • addedInput schema / properties / measurements / items / properties / signed
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "An instrument's Ed25519 signature over this reading, by the rule run_trajectory's input schema gives at segments.",
      +  "properties": {
      +    "alg": {
      +      "enum": [
      +        "ed25519"
      +      ],
      +      "type": "string"
      +    },
      +    "challenge": {
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "instrument": {
      +      "maxLength": 200,
      +      "minLength": 1,
      +      "type": "string"
      +    },
      +    "key": {
      +      "pattern": "^[0-9a-f]{64}$",
      +      "type": "string"
      +    },
      +    "prev": {
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "seq": {
      +      "maximum": 9007199254740991,
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "sig": {
      +      "pattern": "^[0-9a-f]{128}$",
      +      "type": "string"
      +    },
      +    "time": {
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "alg",
      +    "key",
      +    "instrument",
      +    "time",
      +    "seq",
      +    "prev",
      +    "challenge",
      +    "sig"
      +  ],
      +  "type": "object"
      +}
    • changedInput schema / properties / run / properties / initial / description
      Previous value: -"The phase fields of the card at the start of the run, each a number (a vector field is an array of three numbers), and no other key. describe_card gives them, with each unit and bound."New value: +"The phase fields of the card at the start of the run, each a number (a vector field is an array of three numbers), and no other key but signed: an instrument's signature over the rest of initial, under the key \"initial\", by the rule of a segment's signed. describe_card gives the fields, with each unit and bound."
    • addedInput schema / properties / run / properties / segments / items / properties / signed
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "An instrument's Ed25519 signature over this reading, by the rule run_trajectory's input schema gives at segments.",
      +  "properties": {
      +    "alg": {
      +      "enum": [
      +        "ed25519"
      +      ],
      +      "type": "string"
      +    },
      +    "challenge": {
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "instrument": {
      +      "maxLength": 200,
      +      "minLength": 1,
      +      "type": "string"
      +    },
      +    "key": {
      +      "pattern": "^[0-9a-f]{64}$",
      +      "type": "string"
      +    },
      +    "prev": {
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "seq": {
      +      "maximum": 9007199254740991,
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "sig": {
      +      "pattern": "^[0-9a-f]{128}$",
      +      "type": "string"
      +    },
      +    "time": {
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "alg",
      +    "key",
      +    "instrument",
      +    "time",
      +    "seq",
      +    "prev",
      +    "challenge",
      +    "sig"
      +  ],
      +  "type": "object"
      +}
  5. Changed3 schema fields changed
    • changedInput schema / description
      Previous value: -"One run, or one plan of solves, and measurements of one quantity. The answer is the error in numbers, sealed with a hash of the measurements. It holds no verdict. Send run, or solves, not both."New value: +"One run, or one plan of solves, and measurements of one quantity. The answer is the error in numbers, sealed with a hash of the measurements. It holds no verdict. A request holds run or solves, not both."
    • changedInput schema / properties / measurements / description
      Previous value: -"At most 10000. A measurement is compared with the state after landed step k. There is no interpolation and no time matching: map your sample times to steps."New value: +"At most 10000. A measurement is compared with the state after landed step k. There is no interpolation and no time matching: a measurement is placed by its step, its time since the start divided by dt_s."
    • changedInput schema / properties / run / description
      Previous value: -"One anchored run. Total steps must be <= 1000000. Recorded frames must be <= 10000. The shape of initial and of each segment's load depends on the pair: read describe_card for it."New value: +"One anchored run. Total steps must be <= 1000000. Recorded frames must be <= 10000. The shape of initial and of each segment's load depends on the pair: describe_card gives it."
  6. First observed

TDQS

A3.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover only the safety profile (readOnly, idempotent, non-destructive, closed-world), while the description discloses substantial extra behavior: the seal carries no key and leaks nothing about who measured, no threshold is applied, commitment mismatch error codes (CommitmentDoesNotMatch, CommitmentSaltTooShort, CommitmentMalformed, InputMissing), the 1-permit-per-address limit, 60 s answer timeout, the 'Too many concurrent physics tasks' response, and the idempotency of seals. This is rich context well beyond the annotations, and it does not contradict them.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a dense wall of run-on sentences mixing purpose, commitment semantics, seal mechanics, concurrency limits and timeouts. It is front-loaded with the core purpose, but the sheer length and clause-stacking make it hard to parse, and much of the concurrency/timeout material could be trimmed or relocated.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a highly complex tool with nested objects, no output schema, and signing/commitment mechanics, the description covers the important operational facts an agent needs: the two input modes, the seal and commitment lifecycle, error routing, concurrency and timeout behavior. Given there is no output schema, it also characterizes the answer's statistics and seal parts, leaving only minor gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The 6-parameter schema already documents run vs solves, quantity, component, commitment and measurements in depth, and the description largely restates these facts (e.g. the commitment digest recipe appears in both). It adds the framing that a request holds run or solves, not both, but does not materially extend what the schema already provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening states a specific verb+resource: it runs a run_trajectory request without a readout and compares one published quantity against agent measurements at landed steps. This is clearly distinguished from run_trajectory (no readout) and from its own verify-validation sibling that rebuilds the seal from the answer alone. It stops short of a crisp one-line summary, but an agent can identify the tool's function.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit when-to-use / when-not-to-use statement relative to siblings like verify_step, verify_solution, or cite. References to run_dataset ('as run_dataset takes it') and to verify-validation are about parameter form and seal reconstruction, not about selecting this tool over another. Usage must be inferred from the behavioral prose.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources