Skip to main content

Squillify development is paused indefinitely. Read why, and discover what this experiment achieved. Read the story

MicroSkills Reference

Weighted Decision Matrix

business.decision_matrix

ProductionBounded custom (Class B)Deterministicstrictfastv1.0.0
No network

Overview

You send the options and the criteria that decide between them; we return the ranking, every option's score, and the contribution of every criterion to it. Criteria measured in different units — euros, days, a score out of ten — are put on a common footing first, by the method you name per criterion: min-max across the options, share of the total, z-score, a fixed rubric, or none at all. The consequence is worth stating plainly: because normalisation looks at the options in this request, adding or removing an option can change the scores of the others. That is what comparative ranking means, and it is exactly why business.priority_score exists for the absolute case. Equal scores share a rank, competition style, ordered by the tie-break you choose. Degenerate cases are defined rather than divided by zero: one option, or a criterion where every option is equal, is reported as such instead of failing.

Decision matrices are usually built in a spreadsheet, where the normalisation is implicit, the arithmetic is invisible, and nobody notices that the winner changed because a row was added. Publishing the method per criterion, the observed range it normalised over, and the contribution of every criterion to every score turns 'the tool says B' into an argument that can be checked.

Reliability

Fully deterministic and reproducible to the digit: BigDecimal at 34 significant digits, HALF_UP, rounded once to your declared decimal places, no floating point anywhere. Contributions are reconciled to each score by largest remainder, so a breakdown never drifts from the score beside it. Reordering the options changes no score, and under OPTION_ID it changes no ranking either. Degenerate normalisation is defined, not an error: a single option is reported SINGLE_OPTION, a criterion where every option is equal is CONSTANT_CRITERION and scores the same for all of them — so it shifts every score alike and cannot change the order — and a SUM criterion whose values total zero splits equally as ZERO_SUM. Z_SCORE is centred on zero, so scores under it are commonly negative, and so is any LOWER_IS_BETTER criterion, which subtracts. Failures: MATRIX_OPTIONS_INVALID means options cannot be read — none sent, an id that is empty, too long, padded or carrying a control character, a value that is not a decimal, or a value for an undeclared criterion. MATRIX_OPTION_ID_DUPLICATE means an option id appears twice. MATRIX_CRITERIA_INVALID means a criterion is unusable: none sent, a repeated id, a negative weight, FIXED without a scale, a scale whose min is not below its max, or SUM with a negative value. MATRIX_VALUE_MISSING means an option lacks a value for a criterion whose missing is REJECT. MATRIX_NORMALIZATION_UNSUPPORTED means a method outside MIN_MAX, SUM, Z_SCORE, FIXED and NONE. MATRIX_LIMIT_EXCEEDED means more than 500 options or 64 criteria. None is worth retrying unchanged.

Context footprint

The response carries one breakdown row per option and criterion, so it is bounded by options times criteria — 500 by 64 at the ceiling. Ask for fewer criteria, or fewer options, when the response matters more than the detail. A successful call costs 1 execution credit.

When to use it

When you have a shortlist and criteria you can write down, and you need a defensible ranking with the working shown.

When the score must be stable regardless of the other options, when a criterion is really a hard requirement, or when the decision is not reducible to weighted numbers.

Scope

Note
Normalise each criterion across the submitted options, weight them, and return a ranking with every option's arithmetic shown.

Non-goals

  • Does not produce absolute scores: they are relative to the options you sent, and adding or removing one can reorder the rest — business.priority_score is the absolute variant, and shares this skill's weighted-sum engine
  • Does not invent weights, criteria or normalisation you did not declare
  • Does not make the decision, and does not store it
  • Does not fill in a missing value unless you say how

Properties

IdempotentRetry safeStreaming supportedFile input supportedRequires external service

Capabilities

math

Cost & billing

Flat rate per invocation

MetercallsBillable onsuccessCost per call1 credit

File handling

Accepts file_refProduces file_refMax input1 MB

How we handle your data

Sensitive input, safe output
What this means

This skill may receive sensitive content, but it does not target sensitive data and returns only a structured non-sensitive result.

Squillify guarantees
  • Runs inside Squillify
  • This skill runs inside Squillify.
  • Payloads are not sent to an external service by this skill.
  • Squillify does not permanently store submitted payloads.
  • Telemetry records metadata only, not submitted content.
  • Submitted payloads are not used for training.
  • Submitted payloads are not reviewed by humans.
  • This skill does not target sensitive data.
  • The response does not contain submitted content.
Your responsibility

Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.

Read the Microskill Data Handling Policy

Input schema

FieldTypeRequiredDescription
optionsarrayYesBounded array of 1 through 500 closed options, each with unique id and criterion values.
criteriaarrayYesBounded array of 1 through 64 closed criteria declaring weight and normalisation.
tieBreakstringNoHow equal scores are ordered; omit it for INPUT_ORDER.
scaleintegerNoPublished decimal places; omit it for 4.

Output schema

FieldTypeRequiredDescription
rankingarrayYesBounded array of 1 through 500 ranking rows, best first, with shared ranks on ties.
scoresarrayYesBounded array of 1 through 500 score rows in the order the options were sent.
criteriaSummaryarrayYesBounded array of 1 through 64 criterion summaries naming the observed normalisation range.
tieBreakstringYesTie-break actually applied to order equal scores.

API contract

POST /v1/execute
curl
curl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"business.decision_matrix","input":{"options":[{"id":"alpha","values":{"quality":6,"support":10}},{"id":"beta","values":{"quality":9,"support":7}}],"criteria":[{"id":"quality","weight":0.7},{"id":"support","weight":0.3}]}}'
Integrations
TypeScript SDK
import { Squillify } from "@squillify/sdk";

const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });

const { output } = await sq.execute("business.decision_matrix", {"options":[{"id":"alpha","values":{"quality":6,"support":10}},{"id":"beta","values":{"quality":9,"support":7}},{"id":"gamma","values":{"quality":9,"support":7}}],"criteria":[{"id":"quality","weight":0.7},{"id":"support","weight":0.3}]});

Errors

CodeHTTPRetryableDescription
VALIDATION_ERROR400NoThe request payload failed schema validation.
UNAUTHORIZED401NoMissing or invalid API key.
SKILL_NOT_ACCESSIBLE403NoThe API key is not granted access to this skill.
SKILL_NOT_AVAILABLE_FOR_PLAN403NoThis skill is not included in your current plan.
PLAN_ELIGIBILITY_UNAVAILABLE503YesPlan eligibility could not be decided. Retry after backoff.
SKILL_NOT_FOUND404NoThe requested skill or version does not exist.
TENANT_RATE_LIMITED429YesRequest rate limit exceeded. Retry after backoff.
QUOTA_EXCEEDED429YesPlan quota exhausted. Retryable once the quota period resets.
EXECUTION_TIMEOUT504YesExecution exceeded the allowed time budget.
MATRIX_OPTIONS_INVALID400NoThe request payload failed this skill's input validation.
MATRIX_OPTION_ID_DUPLICATE400NoThe request payload failed this skill's input validation.
MATRIX_CRITERIA_INVALID400NoThe request payload failed this skill's input validation.
MATRIX_VALUE_MISSING400NoThe request payload failed this skill's input validation.
MATRIX_NORMALIZATION_UNSUPPORTED400NoThe request payload failed this skill's input validation.
MATRIX_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.

Other limits

LimitValue
Recommended inline bytes32 KiB

Limitations

  • Does not produce absolute scores: they are relative to the options you sent, and adding or removing one can reorder the rest — business.priority_score is the absolute variant, and shares this skill's weighted-sum engine
  • Does not invent weights, criteria or normalisation you did not declare
  • Does not make the decision, and does not store it
  • Does not fill in a missing value unless you say how
  • Scoring one item on its own, or scores that must not move when the set changes — use business.priority_score
  • Comparisons where one criterion is a veto rather than a weight
  • Ranking thousands of rows: this is a decision aid, not a query engine

How to call

POST /v1/execute (requires authentication)

Request bodyjson
{
  "skillKey": "business.decision_matrix",
  "input": {
    "options": [
      {
        "id": "alpha",
        "values": {
          "quality": 6,
          "support": 10
        }
      },
      {
        "id": "beta",
        "values": {
          "quality": 9,
          "support": 7
        }
      },
      {
        "id": "gamma",
        "values": {
          "quality": 9,
          "support": 7
        }
      }
    ],
    "criteria": [
      {
        "id": "quality",
        "weight": 0.7
      },
      {
        "id": "support",
        "weight": 0.3
      }
    ]
  }
}

Examples

Three candidates on quality and support, with two of them tied

Inputjson
{
  "options": [
    {
      "id": "alpha",
      "values": {
        "quality": 6,
        "support": 10
      }
    },
    {
      "id": "beta",
      "values": {
        "quality": 9,
        "support": 7
      }
    },
    {
      "id": "gamma",
      "values": {
        "quality": 9,
        "support": 7
      }
    }
  ],
  "criteria": [
    {
      "id": "quality",
      "weight": 0.7
    },
    {
      "id": "support",
      "weight": 0.3
    }
  ]
}
Expected outputjson
{
  "ranking": [
    {
      "rank": 1,
      "optionId": "beta",
      "score": 0.7,
      "tied": true
    },
    {
      "rank": 1,
      "optionId": "gamma",
      "score": 0.7,
      "tied": true
    },
    {
      "rank": 3,
      "optionId": "alpha",
      "score": 0.3,
      "tied": false
    }
  ],
  "criteriaSummary": [
    {
      "id": "quality",
      "normalization": "MIN_MAX",
      "observedMin": 6,
      "observedMax": 9
    },
    {
      "id": "support",
      "normalization": "MIN_MAX",
      "observedMin": 7,
      "observedMax": 10
    }
  ],
  "tieBreak": "INPUT_ORDER",
  "scores": [
    {
      "optionId": "alpha",
      "score": 0.3,
      "breakdown": [
        {
          "criterion": "quality",
          "rawValue": 6,
          "scaledValue": 0,
          "weight": 0.7,
          "normalizedWeight": 0.7,
          "contribution": 0,
          "direction": "HIGHER_IS_BETTER"
        },
        {
          "criterion": "support",
          "rawValue": 10,
          "scaledValue": 1,
          "weight": 0.3,
          "normalizedWeight": 0.3,
          "contribution": 0.3,
          "direction": "HIGHER_IS_BETTER"
        }
      ]
    },
    {
      "optionId": "beta",
      "score": 0.7,
      "breakdown": [
        {
          "criterion": "quality",
          "rawValue": 9,
          "scaledValue": 1,
          "weight": 0.7,
          "normalizedWeight": 0.7,
          "contribution": 0.7,
          "direction": "HIGHER_IS_BETTER"
        },
        {
          "criterion": "support",
          "rawValue": 7,
          "scaledValue": 0,
          "weight": 0.3,
          "normalizedWeight": 0.3,
          "contribution": 0,
          "direction": "HIGHER_IS_BETTER"
        }
      ]
    },
    {
      "optionId": "gamma",
      "score": 0.7,
      "breakdown": [
        {
          "criterion": "quality",
          "rawValue": 9,
          "scaledValue": 1,
          "weight": 0.7,
          "normalizedWeight": 0.7,
          "contribution": 0.7,
          "direction": "HIGHER_IS_BETTER"
        },
        {
          "criterion": "support",
          "rawValue": 7,
          "scaledValue": 0,
          "weight": 0.3,
          "normalizedWeight": 0.3,
          "contribution": 0,
          "direction": "HIGHER_IS_BETTER"
        }
      ]
    }
  ]
}

Two options where cost is inverted against a fixed rubric and the service level is used as it stands

Inputjson
{
  "options": [
    {
      "id": "in-house",
      "values": {
        "sla": 8,
        "cost": 50
      }
    },
    {
      "id": "managed",
      "values": {
        "sla": 10,
        "cost": 100
      }
    }
  ],
  "criteria": [
    {
      "id": "cost",
      "weight": 1,
      "direction": "LOWER_IS_BETTER",
      "normalization": "FIXED",
      "scale": {
        "min": 0,
        "max": 200
      }
    },
    {
      "id": "sla",
      "weight": 1,
      "normalization": "NONE"
    }
  ]
}
Expected outputjson
{
  "ranking": [
    {
      "rank": 1,
      "optionId": "managed",
      "score": 9.5,
      "tied": false
    },
    {
      "rank": 2,
      "optionId": "in-house",
      "score": 7.75,
      "tied": false
    }
  ],
  "criteriaSummary": [
    {
      "id": "cost",
      "normalization": "FIXED",
      "observedMin": 50,
      "observedMax": 100
    },
    {
      "id": "sla",
      "normalization": "NONE",
      "observedMin": 8,
      "observedMax": 10
    }
  ],
  "tieBreak": "INPUT_ORDER",
  "scores": [
    {
      "optionId": "in-house",
      "score": 7.75,
      "breakdown": [
        {
          "criterion": "cost",
          "rawValue": 50,
          "scaledValue": -0.25,
          "weight": 1,
          "normalizedWeight": 1,
          "contribution": -0.25,
          "direction": "LOWER_IS_BETTER"
        },
        {
          "criterion": "sla",
          "rawValue": 8,
          "scaledValue": 8,
          "weight": 1,
          "normalizedWeight": 1,
          "contribution": 8,
          "direction": "HIGHER_IS_BETTER"
        }
      ]
    },
    {
      "optionId": "managed",
      "score": 9.5,
      "breakdown": [
        {
          "criterion": "cost",
          "rawValue": 100,
          "scaledValue": -0.5,
          "weight": 1,
          "normalizedWeight": 1,
          "contribution": -0.5,
          "direction": "LOWER_IS_BETTER"
        },
        {
          "criterion": "sla",
          "rawValue": 10,
          "scaledValue": 10,
          "weight": 1,
          "normalizedWeight": 1,
          "contribution": 10,
          "direction": "HIGHER_IS_BETTER"
        }
      ]
    }
  ]
}
  • Compare vendors, tools or designs against agreed criteria, reproducibly
  • Show a committee why one option came out ahead, criterion by criterion
  • Re-run a comparison after a weight changes, and see exactly what moved
  • Rank a shortlist where the criteria are measured in different units

Avoid for

  • Scoring one item on its own, or scores that must not move when the set changes — use business.priority_score
  • Comparisons where one criterion is a veto rather than a weight
  • Ranking thousands of rows: this is a decision aid, not a query engine

Composable with

Safety & privacy

  • Runs without calling any external service.
  • Your payloads are never stored permanently.
  • Telemetry captures metadata only — never your payload contents.
  • We never train models on your payloads.
  • No human reviews your payloads.

Tags

decisionanalysisrankingbusiness