diff --git a/openspec/changes/generator-payload-alignment/.openspec.yaml b/openspec/changes/archive/2026-09-02-generator-payload-alignment/.openspec.yaml similarity index 100% rename from openspec/changes/generator-payload-alignment/.openspec.yaml rename to openspec/changes/archive/2026-09-02-generator-payload-alignment/.openspec.yaml diff --git a/openspec/changes/generator-payload-alignment/design.md b/openspec/changes/archive/2026-09-02-generator-payload-alignment/design.md similarity index 100% rename from openspec/changes/generator-payload-alignment/design.md rename to openspec/changes/archive/2026-09-02-generator-payload-alignment/design.md diff --git a/openspec/changes/generator-payload-alignment/proposal.md b/openspec/changes/archive/2026-09-02-generator-payload-alignment/proposal.md similarity index 100% rename from openspec/changes/generator-payload-alignment/proposal.md rename to openspec/changes/archive/2026-09-02-generator-payload-alignment/proposal.md diff --git a/openspec/changes/generator-payload-alignment/specs/cli-generated-rule-delivery/spec.md b/openspec/changes/archive/2026-09-02-generator-payload-alignment/specs/cli-generated-rule-delivery/spec.md similarity index 100% rename from openspec/changes/generator-payload-alignment/specs/cli-generated-rule-delivery/spec.md rename to openspec/changes/archive/2026-09-02-generator-payload-alignment/specs/cli-generated-rule-delivery/spec.md diff --git a/openspec/changes/generator-payload-alignment/specs/cli-layout-export/spec.md b/openspec/changes/archive/2026-09-02-generator-payload-alignment/specs/cli-layout-export/spec.md similarity index 100% rename from openspec/changes/generator-payload-alignment/specs/cli-layout-export/spec.md rename to openspec/changes/archive/2026-09-02-generator-payload-alignment/specs/cli-layout-export/spec.md diff --git a/openspec/changes/generator-payload-alignment/specs/cli-rule-reconciliation/spec.md b/openspec/changes/archive/2026-09-02-generator-payload-alignment/specs/cli-rule-reconciliation/spec.md similarity index 100% rename from openspec/changes/generator-payload-alignment/specs/cli-rule-reconciliation/spec.md rename to openspec/changes/archive/2026-09-02-generator-payload-alignment/specs/cli-rule-reconciliation/spec.md diff --git a/openspec/changes/generator-payload-alignment/specs/cli-rules/spec.md b/openspec/changes/archive/2026-09-02-generator-payload-alignment/specs/cli-rules/spec.md similarity index 100% rename from openspec/changes/generator-payload-alignment/specs/cli-rules/spec.md rename to openspec/changes/archive/2026-09-02-generator-payload-alignment/specs/cli-rules/spec.md diff --git a/openspec/changes/generator-payload-alignment/specs/cli-runtime-rule-execution/spec.md b/openspec/changes/archive/2026-09-02-generator-payload-alignment/specs/cli-runtime-rule-execution/spec.md similarity index 100% rename from openspec/changes/generator-payload-alignment/specs/cli-runtime-rule-execution/spec.md rename to openspec/changes/archive/2026-09-02-generator-payload-alignment/specs/cli-runtime-rule-execution/spec.md diff --git a/openspec/changes/generator-payload-alignment/tasks.md b/openspec/changes/archive/2026-09-02-generator-payload-alignment/tasks.md similarity index 80% rename from openspec/changes/generator-payload-alignment/tasks.md rename to openspec/changes/archive/2026-09-02-generator-payload-alignment/tasks.md index e7e26011..6ca617b8 100644 --- a/openspec/changes/generator-payload-alignment/tasks.md +++ b/openspec/changes/archive/2026-09-02-generator-payload-alignment/tasks.md @@ -9,7 +9,7 @@ green on its own; none depends on a later one to be correct. - [x] 1.2 Make the `delete` not-found message engine-agnostic - [x] 1.3 Correct the seven stale `.taskless//rules/` comments, leaving the two historical ones in the migrations - [x] 1.4 Test deleting a rule filed under each engine, and an id no engine holds -- [x] 1.5 Correct the same stale layout in `cli-runtime-rule-execution`'s spec text (delta written; lands with this change) +- [x] 1.5 Correct the same stale layout in `cli-runtime-rule-execution`'s spec text. **Partially done by the delta**: it corrected only the requirement the delta itself touched, and left the `Blessed runtime rules execute from the materialized run directory` requirement in the same file still naming `.taskless/runtime-rules/`. The remaining sites, here and in `cli-check` and `cli-rule-reconciliation`, were corrected in the archive PR that promoted this change ## 2. Publish the layout table (slice 2) — unblocks the generator @@ -57,10 +57,10 @@ green on its own; none depends on a later one to be correct. - [x] 6.5 Nothing repaired runs in the pass that repaired it. Restore rewrites the working tree and promotes nothing into the current run: an `unsafe` rule stays withheld, a `missing` rule was never a local candidate, and an `unknown` rule never runs. Fetching code and executing it in the same pass that discovered the drift would move the gate - [x] 6.6 A repair that fails is a notice, never a failed `check`. A rule that could not be repaired stays withheld, which is already the safe state -- [ ] 6.7 Ask the generator for `ruleId` on a reconcile `unsafe` entry (**N6**). Until then the id is parsed out of `.taskless/rules/runtime//check.ts`, which works and makes repair depend on a layout that has already moved twice — silently, since a wrong id is a 404 and an unrepaired rule rather than an error +- [x] 6.7 Ask the generator for `ruleId` on a reconcile `unsafe` entry (**N6**). **Done**: `unsafe`, `unknown` and `missing` entries all carry `ruleId`, and `ruleIdFromCheckPath` is deleted. An entry arriving without a usable id is skipped with a notice rather than becoming a request for `undefined`. Until then the id is parsed out of `.taskless/rules/runtime//check.ts`, which works and makes repair depend on a layout that has already moved twice — silently, since a wrong id is a 404 and an unrepaired rule rather than an error ## 7. Close out -- [ ] 7.1 Reply to **N4**: leave the `engine` tier defined and unused — G2 means no engine but `sg` is deliverable as a single file, so the middle rung has no future occupant either -- [ ] 7.2 Grow the changeset as each slice lands; it stays on the bottom branch -- [ ] 7.3 Archive the change on the final slice +- [x] 7.1 Reply to **N4**: **Done**, confirmed both sides — leave the `engine` tier defined and unused — G2 means no engine but `sg` is deliverable as a single file, so the middle rung has no future occupant either +- [x] 7.2 Grow the changeset as each slice lands; it stays on the bottom branch +- [x] 7.3 Archive the change on the final slice diff --git a/openspec/specs/cli-check/spec.md b/openspec/specs/cli-check/spec.md index a76c0073..ae15db09 100644 --- a/openspec/specs/cli-check/spec.md +++ b/openspec/specs/cli-check/spec.md @@ -258,7 +258,7 @@ authentication. `taskless check` SHALL reconcile before running runtime rules whenever a bearer token and a `repositoryUrl` are resolvable and `--anonymous` is not set. It SHALL compute the signature -envelope for the `check.ts` of every runtime rule under `.taskless/runtime-rules/`, call +envelope for the `check.ts` of every runtime rule under `.taskless/rules/runtime/`, call `POST /cli/api/reconcile` with `{ repositoryUrl, files }`, and then execute **only** the runtime rules whose `check.ts` is returned in the `run` set, matched back to local files by signature (per the `cli-rule-reconciliation` capability). Capture `*.yml` and static rules @@ -298,11 +298,11 @@ non-zero code solely because reconciliation failed, and the warning SHALL be sup ### Requirement: Check dispatches static and runtime rules to distinct executors -`taskless check` SHALL dispatch rules to distinct executors by their engine directory: **ast-grep** rules under `.taskless/sg/` via the ast-grep scanner, **Vale** rules under `.taskless/vale/` via the Vale runner (per the `cli-vale-rule-engine` capability), and **runtime** rules under `.taskless/runtime/rules/` via the runtime harness (per the `cli-runtime-rule-execution` capability). Findings from all executors SHALL be aggregated into the same result set and SHALL count toward the exit code identically. +`taskless check` SHALL dispatch rules to distinct executors by their engine directory: **ast-grep** rules under `.taskless/rules/sg/` via the ast-grep scanner, **Vale** rules under `.taskless/rules/vale/` via the Vale runner (per the `cli-vale-rule-engine` capability), and **runtime** rules under `.taskless/rules/runtime/` via the runtime harness (per the `cli-runtime-rule-execution` capability). Findings from all executors SHALL be aggregated into the same result set and SHALL count toward the exit code identically. #### Scenario: Mixed corpus runs all executors -- **WHEN** `.taskless/sg/` contains ast-grep rules, `.taskless/vale/` contains Vale rules, and `.taskless/runtime/rules/` contains runtime rules +- **WHEN** `.taskless/rules/sg/` contains ast-grep rules, `.taskless/rules/vale/` contains Vale rules, and `.taskless/rules/runtime/` contains runtime rules - **THEN** the CLI SHALL run ast-grep rules through `sg scan`, Vale rules through the Vale runner, and runtime rules through the runtime harness - **AND** SHALL merge their findings into one result set diff --git a/openspec/specs/cli-generated-rule-delivery/spec.md b/openspec/specs/cli-generated-rule-delivery/spec.md new file mode 100644 index 00000000..7faf4d73 --- /dev/null +++ b/openspec/specs/cli-generated-rule-delivery/spec.md @@ -0,0 +1,48 @@ +# cli-generated-rule-delivery Specification + +## Purpose + +TBD - created by archiving change generator-payload-alignment. Update Purpose after archive. + +## Requirements + +### Requirement: A delivered rule is a file set + +The CLI SHALL accept a generated rule as a set of files, each with a path relative to +`.taskless/rules///` and its content as text. One shape SHALL serve every engine, +validated against `ENGINE_LAYOUTS` — the table the CLI already holds — so that "is this a complete +rule" is answered from data rather than from per-engine prose. + +A response entry carrying the legacy single `content` object SHALL remain valid and SHALL continue +to be filed as an ast-grep rule. `files` and `content` SHALL be mutually exclusive. + +#### Scenario: A runtime rule arrives complete + +- **WHEN** a delivered rule declares engine `runtime` and carries `check.ts` and `captures/*.yml` +- **THEN** the CLI SHALL write them under `.taskless/rules/runtime//` +- **AND** the rule SHALL be discoverable and verifiable without further input + +#### Scenario: A Vale rule arrives with its config + +- **WHEN** a delivered rule declares engine `vale` and carries `.yml` and `.vale.ini` +- **THEN** the CLI SHALL write both +- **AND** the rule SHALL be scoped by its own `.vale.ini` rather than by a synthesized default + +#### Scenario: An incomplete file set is refused + +- **WHEN** a delivered file set omits a file the engine layout requires +- **THEN** the CLI SHALL refuse the rule and name what is missing +- **AND** SHALL NOT write a partial rule directory + +### Requirement: Delivered paths are refused before they are written + +The CLI SHALL reject an absolute path, any `..` segment, and any path the engine layout does not +account for, **before** creating any directory or file. Writing server-supplied paths is a +directory-traversal surface that did not exist while the response carried one structured object +whose destination the client computed itself. + +#### Scenario: A traversing path is refused + +- **WHEN** a delivered file declares a path containing `..` or an absolute path +- **THEN** the CLI SHALL refuse the entire rule +- **AND** SHALL NOT have created any file or directory for it diff --git a/openspec/specs/cli-layout-export/spec.md b/openspec/specs/cli-layout-export/spec.md new file mode 100644 index 00000000..344764eb --- /dev/null +++ b/openspec/specs/cli-layout-export/spec.md @@ -0,0 +1,35 @@ +# cli-layout-export Specification + +## Purpose + +TBD - created by archiving change generator-payload-alignment. Update Purpose after archive. + +## Requirements + +### Requirement: The rule layout is published as data + +The CLI SHALL publish its rule-layout table — the known engines, each engine's rule file, config +file and captures directory, and the rules and tests directory names — as an importable module, +so that a service building a rule payload validates against the table rather than transcribing it. + +A shape documented in prose drifts: the same layout was described in seven stale code comments and +in the runtime-execution spec, all naming a pre-migration path. A shape published as data does not. + +#### Scenario: The layout is importable + +- **WHEN** a consumer imports the published layout entry +- **THEN** it SHALL receive the engine list and each engine's layout as values +- **AND** the values SHALL be the same ones the CLI itself dispatches on + +### Requirement: The published layout carries no CLI runtime + +The published entry SHALL NOT reach the filesystem, the network, telemetry, or the command tree, +so a Worker can import it. This SHALL be enforced by the build — the published chunk graph is +checked at build time, failing the build rather than relying on review — matching how the prompts +entry is already constrained. + +#### Scenario: A runtime import fails the build + +- **WHEN** the published layout graph reaches a host capability +- **THEN** the build SHALL fail +- **AND** the artifact SHALL NOT be emitted diff --git a/openspec/specs/cli-rule-reconciliation/spec.md b/openspec/specs/cli-rule-reconciliation/spec.md index 5d4c1170..e6e7fb6f 100644 --- a/openspec/specs/cli-rule-reconciliation/spec.md +++ b/openspec/specs/cli-rule-reconciliation/spec.md @@ -112,13 +112,13 @@ inert data, always available, and SHALL NOT be reported to or gated by reconcili SHALL reconcile by sending `POST /cli/api/reconcile` with an `Authorization: Bearer ` header and a JSON body `{ repositoryUrl, files }`, where `repositoryUrl` is the full repository URL and `files` is an array of `{ file, signature }` covering the `check.ts` of **every** -runtime rule the CLI holds under `.taskless/runtime-rules/`. `file` SHALL be the `check.ts`'s +runtime rule the CLI holds under `.taskless/rules/runtime/`. `file` SHALL be the `check.ts`'s delivered path as it exists on disk and `signature` SHALL be the full envelope computed for its bytes. The CLI SHALL send the whole signature envelope, not a bare digest. #### Scenario: Every runtime rule's check.ts is reported -- **WHEN** the CLI reconciles with runtime rules present under `.taskless/runtime-rules/` +- **WHEN** the CLI reconciles with runtime rules present under `.taskless/rules/runtime/` - **THEN** the request body SHALL include one `{ file, signature }` entry for the `check.ts` of each runtime rule #### Scenario: Inert files are not reported @@ -222,3 +222,43 @@ signal. The server-side record is authoritative and the server decides what runs - **WHEN** a rule file has a locally stored signature that matches its content - **THEN** the CLI SHALL NOT run the file on that basis alone - **AND** SHALL rely on the server's `run` set for authorization + +### Requirement: The reported file path is contractual + +The CLI SHALL report each runtime check to reconcile as a **repo-root-relative POSIX path**, +`.taskless/rules/runtime//check.ts`, with platform separators normalized so every host +reports the same string for the same rule. + +This is a cross-team contract, not an implementation detail. Reconcile matches `run` by content +digest and is path-independent, but the `unsafe` versus `unknown` split is a lookup on the +reported name: a spelling mismatch downgrades a tampered file from `unsafe` ("content changed in +place") to `unknown` ("never issued") — a diagnostic loss on the one path where the diagnosis +matters. + +#### Scenario: The reported path is repo-relative and POSIX + +- **WHEN** the CLI reports a runtime check to reconcile +- **THEN** the `file` SHALL be `.taskless/rules/runtime//check.ts` +- **AND** the separators SHALL be `/` regardless of host platform + +### Requirement: A withheld rule can be re-fetched + +When reconcile reports a rule as `unsafe` or `unknown`, the CLI SHALL be able to request the +blessed bytes for that rule rather than only warning. The request SHALL carry the rule id **and** +the signature the client holds, scoped like reconcile itself, so that a bare digest cannot be used +to retrieve content across organizations. + +The response SHALL be the bytes matching the held signature, never the newest generation. +Answering with newer bytes would upgrade a rule in the middle of a `check` without anyone asking; +upgrading is regeneration and SHALL remain an explicit action. + +#### Scenario: An unsafe rule is repaired + +- **WHEN** reconcile reports a rule as `unsafe` +- **THEN** the CLI SHALL be able to re-fetch the blessed bytes for that rule +- **AND** the rule SHALL reconcile as `run` after the bytes are restored + +#### Scenario: Re-fetch does not upgrade + +- **WHEN** a newer generation of the same rule exists server-side +- **THEN** re-fetch SHALL still return the bytes matching the signature the client reported diff --git a/openspec/specs/cli-rules/spec.md b/openspec/specs/cli-rules/spec.md index 0598e917..0353ff95 100644 --- a/openspec/specs/cli-rules/spec.md +++ b/openspec/specs/cli-rules/spec.md @@ -206,12 +206,26 @@ The API calls for rule generation (`POST /cli/api/request` and `GET /cli/api/req `taskless rule delete ` SHALL remove the rule and everything that defines it. Under the rule-directory layout that is one directory, `.taskless/rules///`, which carries the rule, any per-engine config, and its tests. (Renamed; repathed.) Accepts `--anonymous` as a no-op. +A rule id does not carry its engine, so the CLI SHALL **resolve** which engine directory holds `` rather than assuming one. A rule id is globally unique by construction, so at most one engine can hold it. When no engine holds the id, the CLI SHALL report not-found without naming an engine, because naming one would be a guess. + #### Scenario: Deleting a rule removes its whole directory - **WHEN** a user runs `taskless rule delete no-eval` - **THEN** the CLI SHALL remove the rule's directory including its `.tests/` - **AND** no file belonging to that rule SHALL remain +#### Scenario: Deleting a rule filed under any engine + +- **WHEN** a rule with id `` exists under `.taskless/rules/vale//` or `.taskless/rules/runtime//` +- **THEN** `taskless rule delete ` SHALL remove that directory +- **AND** SHALL NOT report not-found for a rule that is present on disk + +#### Scenario: Deleting an id no engine holds + +- **WHEN** no engine directory contains `` +- **THEN** the CLI SHALL report the rule was not found under `.taskless/rules/` +- **AND** the message SHALL NOT name a single engine's path + ### Requirement: Rules delete does not require authentication `taskless rule delete` SHALL NOT require authentication. Deleting a local file is not a service operation. (Renamed.) diff --git a/openspec/specs/cli-runtime-rule-execution/spec.md b/openspec/specs/cli-runtime-rule-execution/spec.md index b4b8d546..e8b67b15 100644 --- a/openspec/specs/cli-runtime-rule-execution/spec.md +++ b/openspec/specs/cli-runtime-rule-execution/spec.md @@ -8,26 +8,46 @@ Defines how the CLI executes a **runtime rule** in `taskless check`: the on-disk ### Requirement: Runtime rules are directories recognized by metadata -The CLI SHALL recognize a **runtime rule** as a directory under `.taskless/runtime/rules//` -containing one or more ast-grep capture `*.yml` (one per capture rule) and a single `check.ts`, -its capture rules declaring `metadata.taskless.kind: runtime`. The rule's check file SHALL be -the `check.ts` in the rule directory. The CLI SHALL read **each capture rule's** -`metadata.taskless.match` (`anchor` or `broad`) to select that capture rule's ast-grep -invocation mode; capture rules within one runtime rule MAY mix modes (each is independent). -Rule files under `.taskless/sg/rules/` SHALL continue to be treated as static ast-grep rules, -not runtime rules. `.taskless/runtime/rule-tests//` holds `valid/` and `invalid/` -verification fixtures and SHALL NOT be executed by `check`. +The CLI SHALL recognize a **runtime rule** as a directory under `.taskless/rules/runtime//` +containing a `captures/` directory of one or more ast-grep capture `*.yml` (one per capture rule) +and a single `check.ts`, its capture rules declaring `metadata.taskless.kind: runtime`. The rule's +check file SHALL be the `check.ts` in the rule directory. The CLI SHALL read **each capture rule's** +`metadata.taskless.match` to select that capture rule's ast-grep invocation mode; capture rules +within one runtime rule MAY mix modes (each is independent). + +A `match` value the build does not implement SHALL be **refused**, never coerced to a default. The +modes scan different things — `anchor` is a syntactic narrow, `broad` a whole-language enumerator — +so substituting one for another reinterprets the capture rather than degrading it, and the shortfall +would be reported as a clean pass. The refusal SHALL be per capture file, not per rule, so one +unimplemented mode does not remove a rule's other narrows. + +Rule files under `.taskless/rules/sg/` SHALL continue to be treated as static ast-grep rules, +not runtime rules. A rule's `.tests/` directory holds verification fixtures and SHALL NOT be +executed by `check`. #### Scenario: A runtime directory entry is a runtime rule -- **WHEN** `.taskless/runtime/rules//` contains capture `*.yml` with `metadata.taskless.kind: runtime` and a `check.ts` +- **WHEN** `.taskless/rules/runtime//captures/` contains `*.yml` with `metadata.taskless.kind: runtime` and the directory has a `check.ts` - **THEN** the CLI SHALL treat it as a runtime rule with `check.ts` as its check file and route it to the runtime harness #### Scenario: Rules under sg remain static -- **WHEN** a rule file lives under `.taskless/sg/rules/` +- **WHEN** a rule file lives under `.taskless/rules/sg/` - **THEN** the CLI SHALL treat it as a static rule and SHALL NOT route it to the runtime harness +#### Scenario: An unimplemented match mode is refused + +- **WHEN** a capture rule declares a `match` value this build does not implement +- **THEN** the CLI SHALL NOT load that capture rule +- **AND** SHALL NOT treat it as `anchor` +- **AND** the rule's other capture rules SHALL still load + +#### Scenario: verify explains a refused capture + +- **WHEN** `taskless verify` inspects a rule holding a capture with an unimplemented `match` value +- **THEN** verification SHALL fail +- **AND** the error SHALL name the capture file, the offending value, and the modes this build implements + ### Requirement: The harness narrows with one ast-grep scan and gates on matches For a runtime rule the CLI SHALL assemble the rule's capture rules into an ast-grep @@ -132,11 +152,58 @@ toward the exit code identically to static findings. `Finding.severity` (`error` When a runtime rule is executed on a validated path, the CLI SHALL execute it from the ephemeral, gitignored `.taskless/.run/` materialization of the blessed bytes, not from the -live `.taskless/runtime-rules/` tree, so the bytes executed are the exact bytes reconciliation +live `.taskless/rules/runtime/` tree, so the bytes executed are the exact bytes reconciliation blessed (read-hash-execute ordering). #### Scenario: Execution uses the blessed bytes - **WHEN** a runtime rule is blessed and executed - **THEN** the CLI SHALL invoke the `check.ts` materialized under `.taskless/.run/` -- **AND** SHALL NOT execute a copy modified in `.taskless/runtime-rules/` after reconciliation +- **AND** SHALL NOT execute a copy modified in `.taskless/rules/runtime/` after reconciliation + +### Requirement: A runtime rule has exactly one executable file + +The CLI SHALL refuse a runtime rule whose directory contains any module file other than +`check.ts`. `check.ts` is the only executable surface of a runtime rule and the only artifact +carrying a signature, so any other module would be code reachable from a blessed entry point +without itself being blessed — one relative import away, while tampering with it leaves +`check.ts` still matching its blessed digest. The generator commits to emitting exactly one; +this requirement makes the guarantee enforced rather than trusted. + +"Module file" SHALL cover every extension a check could import, not only `.ts`: the loader +transpiles TypeScript, but a `.js` sibling resolves just as readily. + +The search SHALL be recursive. "One import away" is not "one directory away" — a single +`import "./lib/helper.ts"` reaches an arbitrarily deep relative path in one hop — so a search +bounded to the rule root would let any nested directory carry unsigned code past the check while +`check.ts` still matched its blessed signature. The search SHALL also consider only files, so a +directory whose name ends in a module extension is not reported as one. + +The rule's `.tests/` directory SHALL be excluded from this search. A runtime check reads real +files under a root, so a fixture that is itself TypeScript is the normal case rather than a +smuggled helper, and refusing it would break correct rules — a worse failure than the one being +prevented. + +#### Scenario: A helper module beside check.ts is refused + +- **WHEN** a runtime rule directory contains `check.ts` and any other module file, at any depth +- **THEN** the CLI SHALL refuse the rule and name the offending file +- **AND** SHALL NOT execute its `check.ts` + +#### Scenario: A TypeScript test fixture is not a stray module + +- **WHEN** a runtime rule carries a `.ts` file under its `.tests/` directory +- **THEN** the CLI SHALL still discover and run the rule + +### Requirement: Declared versions are read + +The CLI SHALL read `RUNTIME_CHECK_PROTOCOL_VERSION` against a delivered check's declared protocol +version, and `metadata.taskless.version` on a capture rule, refusing what it does not implement. +Both values exist today and are read by nothing, so a payload declaring a future contract is +executed against the current one. + +#### Scenario: A future protocol version is refused + +- **WHEN** a runtime rule declares a check protocol version this build does not implement +- **THEN** the CLI SHALL refuse the rule and state the version it expected +- **AND** SHALL NOT invoke the check with the current argument shape