← Plugin catalog
Productivity

Vertical Bar Agent

Vertical Bar Inc v0.13.8

Publisher description

From the marketplace listing

Vertical Bar Agent helps authorized teams inspect CrossCheck snapshots and process-mining data, analyze dependencies and telemetry, build grounded Briefings, manage test suites and release packages, and run governed NetSuite workflows through ChatGPT. It also helps author and publish Stress Test contracts, open their CrossCheck page to start a Run, and inspect Run progress and results. Agent-started Stress Test runs are available only in active sandbox or release-preview environments.

Language: English · Automatically detected from descriptions.

Files & skills

File archives

Plugin package8 files · 19.1 KBBrowse files →
Skill instructions
briefing17.8 KB

View saved version →

---
name: briefing
description: Produce a Briefing — a self-contained, interactive, on-brand HTML analysis artifact for ANY analysis goal that draws on CrossCheck and/or Vertical Bar data, grounded in real data, and publish it to the in-product Briefing surface. Use whenever an operator wants an analysis / diagnostic / report (over CrossCheck or Vertical Bar sources) they can SEE and trust on the product surface (close health, order-to-cash, AR aging, spend, anomalies, customizations, lineage — any domain). Domain-agnostic on the question; scoped to CrossCheck/Vertical Bar data. NOT tied to month-end close.
---

# Briefing — author & publish an analysis surface

Turn a user's analysis goal into a **self-contained interactive HTML Briefing**, grounded in real data, and publish it to the dashboard's Briefing surface (`/[org]/[ws]/briefings`).

**Domain-agnostic.** A Briefing is the SURFACE + the free-authoring, NOT a fixed report type. The same skill produces a close diagnostic, an order-to-cash process map, an AR-aging view, a spend anomaly brief — whatever the goal is. Do not couple the skill to any one domain.

> The agent owns judgment + visualization; the platform owns only the thin sandboxed render surface (`<iframe sandbox="allow-scripts">`). Quality bar: bespoke visuals by composition, never a templated catalog. Separation: data acquisition/detection is deterministic (every figure traces to a query); authoring is free.

## Method — any analysis, any data

0. **Inspect `runtime_info`, then resolve authorized scope.** On the hosted remote surface, the MCP
   request already carries verified identity: do not look for `login`, a local browser, a token
   cache, or a window. On an installed local surface, use `login` only when `runtime_info` reports
   that Cognito identity is absent and the reported runtime supports login. In every case, discover
   workspace scope with `cc_workspaces`; no environment value or remembered workspace is authority.
1. **Understand the goal, then CHOOSE the data the question needs.** Acquire it ONLY through CrossCheck's **authenticated, read-only HTTP GET proxies** — the platform runs the read server-side and returns JSON; **the skill never touches a database or NetSuite directly, never holds DB credentials, never issues raw SQL against a database**:
   - the **live read proxy** (`/api/v1/live-read`) — SuiteQL-as-a-GET over live NetSuite, for fresh reads;
   - the **landed-data read proxy** (`/api/v1/briefings-data`) — the same shape over CrossCheck's **landed** close event-store (read-only, workspace-scoped; "psql-as-a-GET");
   - CrossCheck read APIs (snapshots / customizations / dependencies / employees) and Vertical Bar process data via their read surfaces.
   All reads ride the existing CrossCheck / Vertical Bar Cognito session. The skill is handed a **thin GET surface, never DB credentials**. The Briefing surface owns authoring + publish, NOT data ownership.
2. **Acquire read-only, coverage-first + ground.** Pull what's actually present for the account; **state gaps honestly** (never silently drop a finding); every figure carries provenance (its source table/query).
3. **Assemble a grounded bundle** = `{ goal, account, generated_at, coverage{available,missing}, facts: {<key>:{value, unit?, provenance}}, series, findings }`.
4. **Free-author a self-contained interactive HTML.** Inject the grounded data inline and read every authoritative figure FROM it — **never free-type a number**. But this is an **internal authoring discipline: NEVER surface the mechanism in the rendered output** — no `window.__BRIEFING_DATA__`, no "references the bundle", no data-block plumbing text. The **only** user-facing provenance is a per-figure **ⓘ tooltip citing the source/detector** (e.g. "Detector B4 — systemnote × employees"); the implementation stays invisible. **Product chrome** (headers, cards, layout, labels) uses CrossCheck `--cc-*` design tokens — no hex on chrome; **data-encoding palettes (chart colors) are free**. **Charts via the vendored viz runtime, auto-inlined.** Put the single marker `<!--BRIEFING_VIZ-->` in `<head>` and author charts against the global `window.d3` (alias `window.BriefingViz`) — a curated, eval-free **d3** toolkit (scales, color, shape, axes, force, drag, zoom, hierarchy, **sankey**). `briefing_publish` splices the ~200KB runtime in at the marker, so you NEVER paste the library yourself; without the marker no runtime is added. The sandbox blocks the network, so this inline path is the only one — do not reference a CDN or `<script src>`. Use it for flow diagrams (`d3.sankey`); hand-rolled SVG/CSS stays fine for simple KPI/bar. For clean, **non-overlapping flowcharts / decision trees / dependency graphs**, prefer **`briefing_layout`** (give it mermaid text or a generic `{nodes,edges}` model → embed the returned snippet) over hand-rolling `d3.forceSimulation`. Compose freely (KPI grid, charts, tables, process/flow diagrams, findings, honest caveats) — bespoke over a fixed catalog.
5. **Self-review (output-blind), then publish — don't screenshot into the chat.** Re-read the assembled HTML against the Acceptance checklist below (every figure cited, ≥1 bespoke visual, no duplicate findings/raw dumps, on-brand `--cc-*` chrome, ≥1 process/flow diagram where the domain has process data) and fix what fails. Do **NOT** spin up headless Chrome / puppeteer to render the artifact to a PNG and surface it in the chat — that is not the deliverable; the published `viewUrl` is where the human sees the real render. A capable installed runtime may open that URL as a best-effort convenience; a hosted runtime returns it for the agent to surface. A pre-publish render is **opt-in only** — reserve it for a layout you have a specific reason to doubt, and even then keep it to yourself.
6. **Publish — the DEFAULT terminal step (opt-out only).** The end of every analysis is `briefing_publish({title, account, html, workspaceId})` → `{ id, viewUrl, rawUrl, workspace }`; do this unless the user explicitly said not to. **When re-publishing an iteration of an earlier analysis, pass a stable `topic` key** (an optional string) so the platform stacks the new artifact as the next *version* of that same topic instead of a fresh, unrelated briefing (RND-3056); an optional `note` can describe what changed in this version. **Pass the SAME `workspaceId` you chose in scope discovery**; no ambient publish scope exists. The result echoes the resolved `workspace` when available — **confirm it is the workspace the goal targeted** before surfacing the link. `viewUrl` is the human dashboard page `/[org]/[ws]/briefings/<id>`; the installed runtime may auto-open it, while a hosted runtime returns it without attempting local UI. `rawUrl` is the auth-gated raw artifact. Surface the `viewUrl` to the user as the deliverable. The artifact carries its own theme (the sandbox can't read the parent's).

### Data paths that enrich results (easy to miss)

**Call `briefing_schema` FIRST — it is the runtime source of the specific data-path map** (which landed
table, which column, which cross-product join key) for the account you are analyzing. It returns
`{ tables, joinGraph, dataPaths, detectors }`; wire the ones the goal needs (not a prescription). Keep
these path-shaped reminders in mind and let `briefing_schema` supply the exact table/column/key names:

- **Actor ids are LANDED — don't default to a name-only join.** Resolve a process actor to a
  CrossCheck employee reference-first (the landed actor/creator keys are in `briefing_schema.dataPaths`
  → `actor-identity`); integrations resolve by name via `cc_employees`. A live `systemnote` read
  (`cc_live_read`) is the narrow fallback ONLY for a not-yet-landed human status-changer.
- **There is a 2nd cross-product bridge beyond the transaction id** — see `briefing_schema.joinGraph`.
- **Landed close tables are environment-scoped** — group by environment for multi-env work
  (subsidiary ≠ environment); `briefing_schema` gives the exact keying.
- **`$` amounts are coverage-gated** — posting txns carry GL; non-posting Sales Orders have none.
  State the gap; never invent a figure. (`briefing_schema.dataPaths` → `amount-coverage`.)
- **Live-read is budget 1/NetSuite-account, fail-closed** — prefer landed data; never parallel-run
  the same account.

## Tools (the current agent MCP)

The installed plugin and hosted remote MCP expose the same workspace-explicit analysis tools. Call
`runtime_info` instead of inferring which surface is active. **Reads are HTTP proxies the platform
runs server-side; the skill never holds DB/NetSuite credentials and never issues SQL against a
database directly.**

- **`login({ email?, password? })` — installed surfaces only.** If `runtime_info` reports a local
  surface with no Cognito identity, no args opens browser OAuth; explicit email+password is the Node
  SRP compatibility path. The hosted remote surface has verified request identity and deliberately
  exposes no `login` or `logout`. `whoami` shows current auth and workspace routing mode.
- **`briefing_data_query({ sql, limit?, environmentId? })`** — read-only `SELECT`/`WITH` over the platform's landed analytical stores ("psql-as-a-GET"), and the ONLY data-query tool. The platform runs it server-side, workspace-scoped, and returns `{ rows, rowCount, truncated, source }`. WHICH store answers is decided server-side from the relations you name (names via `briefing_schema`); a single statement cannot span two stores. Pass `environmentId` when the workspace has more than one and the statement reads process data. **This is NOT a database connection** — it is a guarded read proxy, and a refusal is never an empty result.
- **`cc_live_read({ sql, limit? })`** — read-only SuiteQL `SELECT` against **live** NetSuite, proxied through CrossCheck. Use for fresh reads the landed store does not have.
- **`briefing_layout({ mermaid? | model?, opts? })`** → `{ snippet, summary }` — compute a deterministic, **non-overlapping** graph/flow layout at **publish time** (dagre, in Node) and get back a ready-to-embed HTML `snippet` (the artifact ships **no** layout engine — only coordinates + the bundled renderer). Provide EXACTLY ONE of: `mermaid` (flowchart subset — `graph/flowchart TD|LR`; shapes `[] () ([]) {} (())`; edges `--> --- -.-> ==>` + `-->|label|`; chains) OR `model` (generic `{ nodes:[{id,label?,shape?}], edges:[{from,to,label?,style?}] }`). **Data-agnostic** — you map ANY analysis (dependencies, process steps, decision trees, …) into the generic model yourself. For a **swimlane** (lane-banded flow by actor / phase / type — e.g. SYS·AR·AP·ACCT), pass `opts:{layout:'swimlane', lanes:[{id,label?,color?}], laneAxis?:'row'|'col'}` and a `lane` on every node (model-direct; mermaid stays flow-only). Embed the returned `snippet` verbatim in your `<body>` and keep `<!--BRIEFING_VIZ-->` in `<head>`. ELK is reserved and fails loud.
- **`briefing_publish({ title, account?, html, topic?, note? })`** → `{ id, viewUrl }` — publish the self-contained artifact to the in-product Briefing surface. Pass a stable `topic` to stack this as the next version of the same topic (RND-3056). `briefing_list` lists published Briefings (metadata only).
- **`cc_*`** — governed CrossCheck tools. The analysis surface remains read-only: `cc_workspaces`, `cc_list_snapshots`, `cc_get_snapshot`, `cc_list_customizations`, `cc_get_suitescript_source`, `cc_dependencies`, `cc_dependency_summary`, `cc_dependency_chain`, `cc_dependency_paths`, `cc_dependency_graph`, `cc_dependency_graph_status`, `cc_impact_analysis`, `cc_employees`, `cc_script_telemetry`. The narrow deployment-mutation exception is described below.
- **`vb_*`** — Vertical Bar process mining, all FIXED-SHAPE (Cognito only): `vb_workspaces`, `vb_projects`, `vb_process_overview`, `vb_variants`, `vb_cases`, `vb_episode_variants`. There is **no `vb_data_query`** — the flexible read-only SQL path over process data is **`briefing_data_query`**, which reaches it through CrossCheck; see the data-path note below. `vb_episode_variants({ workspaceId, primary_types, time_range, anchor?, max_hops?, max_variants?, max_edges?, max_exceptions?, max_primary_objects?, statement_timeout_seconds?, poll_interval_ms?, timeout_ms? })` wraps the async PA `close.getVariants` job API for transaction-type episode summaries. It requires an explicit `workspaceId` from `vb_workspaces`; no ambient scope fallback exists. It sends a workspace-scoped deterministic idempotency key, polls only the returned relative `/insights/close-analytics/jobs/{job_id}` path, and returns bounded `summary`, `variants`, aggregated top `edges`, `exceptions`, `provenance`, counts/caps/truncation metadata, workspace echo, and a limitation string. Treat it as episode-summary evidence only: it is **not** full process-map network parity, not a case timeline/list or edge drilldown, not a close attestation, and not a backend capacity fix (network parity is RND-2800; backend capacity hardening is RND-2801).

### Deployment tool pack (RND-2907)

Nine workspace-scoped tools cover the governed deployment walkthrough. Reads:
`cc_list_ci_workflows`, `cc_get_ci_workflow`, `cc_get_env_snapshot_git_source`,
`cc_list_release_packages`, `cc_get_release_package`, `cc_get_ci_workflow_run`. Mutations:
`cc_create_release_package`, `cc_add_release_package_items`, `cc_start_ci_workflow_run`.

All nine use the same routing as the other CrossCheck tools: pass the `workspaceId` returned by
`cc_workspaces`. A Cognito user must have the server-authorized scopes for each operation.

Each mutation is a single direct server call — there is no client-side `confirm`/preflight; the
server enforces its own guards and its response (including any error) is surfaced verbatim. Start-run
requires an identified Cognito user. Demo order: establish identity only when `runtime_info` says the
installed runtime needs it → resolve the snapshot Git source → create package →
add items → get package/closure → start run → poll run. The full start→observe flow (strict
all-target Review, staged A→B) needs PR #833 in the target deployment; before that, start-run
returns `RUN_ENGINE_NOT_READY` (503). Approval is intentionally absent and stays in the web UI.

**Scope discovery — do this FIRST, never hardcode a workspace.** Call **`cc_workspaces`** (and
`whoami`) to enumerate the workspaces authorized by the Cognito identity. Use the sole result
automatically. If more than one is returned and the user's request does not already identify one,
ask the user to choose by safe name; never pick the first or guess. **Thread that returned
`workspaceId` to BOTH every data tool AND `briefing_publish`** — analyze and publish into the same
workspace. No ambient workspace scope exists. Confirm the `workspace` the publish result echoes back
matches the target. A `WORKSPACE_SCOPE_REQUIRED` refusal means perform this discovery and retry the
original tool once. Use **`cc_live_read`** (the governed proxy — rate-limited, audited, row-capped)
for live reads; it is the only live-NetSuite path.

**CrossCheck × Vertical Bar (data path, not a prescribed analysis).** The two products mine the **same** NetSuite transactions: CrossCheck carries *state / structure / outcome* (config, close-state, GL, lineage, what changed), Vertical Bar carries *process* (how a transaction flowed — activities, throughput, rework loops). They join on the **NetSuite transaction internalId**, **transaction-scoped** (a period-close event itself has no VB case). **The exact join keys are table-specific and easy to get wrong — get them from `briefing_schema.joinGraph`, don't guess** (there is also a 2nd bridge for audit-trail events). Reach the process side two ways: the fixed `vb_*` endpoints (workspace-scoped map / variants / cases — they take a backboneType, not a projectId), or **`briefing_data_query`** = open read-only SQL, which serves the whole process corpus through CrossCheck — the event log, the backbone transaction registry (so you can scope a question to one document type) and the transition relation with per-step durations (for bottlenecks, rework and throughput). It carries *all* transaction object types, not just Sales Order, and those three join to each other in a **single** statement. `briefing_data_query` is the **single** data-query tool: the platform picks which store answers from the relations you name, so a single statement can never span the two stores — run one per store and join the results yourself. Process data is published **per environment**: pass `environmentId` when the workspace has more than one, and treat an explicit refusal as "nothing is published here", **never** as "no process data exists". Coverage is bounded to VB's ingest window (∩ the CrossCheck window); when a join returns 0 rows, distinguish out-of-window from no-relationship. Survey BOTH products in scope discovery before concluding a goal is single-product.

## Example analyses (illustrative — NOT the skill's scope)

The method above is identical for every domain; these are just example detector sets a goal might use:

- **Close health** — period-state lag/blitz, owner-identity-join (systemnote actor × `employees`), task rework, late-JE timing, GL trial-balance; + VB process where relevant.
- **Order-to-cash** — VB process states/variants/durations/bottlenecks (the VB transaction-status field; see `briefing_schema`) + CC GL trial-balance.
- **AR aging / spend / anomaly / config-impact / lineage / …** — pick the data + detectors the question demands.

Domain-specific detector queries are **reference content**, never the skill's identity. Add new domains by adding data/detectors, not by forking the skill.

## Acceptance — the human pixel gate (output-blind)

1. every authoritative figure correct + cited — zero "evidence unavailable"; 2. ≥1 bespoke visual a fixed catalog could not express; 3. no duplicate findings / raw dumps; 4. on-brand `--cc-*` chrome; 5. ≥1 data-grounded process/flow diagram where the domain has process data. A prior PoC is a yardstick, never a template (don't copy its composition).
deployment5 KB

View saved version →

---
name: deployment
description: Assemble a CrossCheck Release Package and run it through a CI workflow — create the package, add customization items, then start a workflow run and follow it. Use when the user wants to deploy, promote, or release NetSuite customizations between environments, asks what a release contains, wants a CI workflow started or its run status, or says deploy / release / promote / 배포 / 릴리스. These are the only mutating tools this plugin exposes; read the authorization rules below before calling one.
---

# Deployment — release packages and CI workflow runs

Four read tools and three that mutate. The mutating three are the **only** writes this plugin
performs against CrossCheck, and they are governed differently from everything else here.

| Tool | Kind | Requires |
| --- | --- | --- |
| `cc_list_release_packages`, `cc_get_release_package` | read | workspace scope |
| `cc_list_ci_workflows`, `cc_get_ci_workflow`, `cc_get_ci_workflow_run` | read | Cognito identity + workspace scope |
| `cc_create_release_package` | **MUTATES** | `deploy:write` |
| `cc_add_release_package_items` | **MUTATES** | `deploy:write`, package still a draft |
| `cc_start_ci_workflow_run` | **MUTATES** | an **identified Cognito user** |

## The authorization rule that trips people

`cc_start_ci_workflow_run` needs a real signed-in human. This is a server guard, not a client check,
so you cannot work around it and should not try.

When a run is refused for identity, call `runtime_info` before choosing the recovery path. On an
installed local surface, use the **`setup`** skill to sign in, then retry. On a hosted remote surface,
`setup` and `login` do not exist: ask the user to reconnect or reauthorize the MCP connector in the
host, then retry only after `runtime_info` / `whoami` reports verified request identity. Do not report
an identity refusal as a workflow problem.

Call `cc_start_ci_workflow_run` only for the deployment intent the user explicitly requested in the
current conversation. Some hosts additionally require fresh human interaction for every call; that
host prompt is a safety aid, not authorization authority. It does not approve a Pipeline stage.
Stage approval still happens in CrossCheck, by a person. Never imply the plugin can approve that
stage.

## The order, and why it is the order

1. **Resolve workspace routing from `runtime_info`.** Call `cc_workspaces`: use the
   sole result automatically. If more than one is returned, ask the user to choose by safe name.
   Never select the first, invent an id, or reuse one after the conversation changes workspace.
2. **`cc_create_release_package`** `{workspaceId?, name, description?, environmentId?}` — returns the
   server response unchanged, including the package id you will need next.
3. **`cc_add_release_package_items`** `{workspaceId?, packageId, items[]}` — the response carries
   `autoInclude.status`. **Read it.** CrossCheck may pull in dependencies you did not list, and that
   set is what will actually deploy. Report what `autoInclude` added, not what you asked for.
   Items can only be added while the package is a **draft**; a package past that state refuses, and
   the refusal is the server's, so surface it verbatim rather than retrying.
4. **`cc_list_ci_workflows`** / **`cc_get_ci_workflow`** — pick the workflow and read its ordered
   stages. `cc_get_ci_workflow` joins each stage to its environment name, which is the only readable
   way to confirm a promotion is aimed where the user thinks it is. Confirm the target environment
   with the user before step 5 whenever the workflow touches production.
5. **`cc_start_ci_workflow_run`** `{workspaceId?, workflowId, packageId}` — the request body is exactly
   the package id. The host must ask a person immediately before this call. Returns the server
   response unchanged; actual environment writes remain blocked on CrossCheck stage approval.
6. **`cc_get_ci_workflow_run`** — poll for status. A started run is not a finished one; do not report
   a deployment as done from the start call's response.

## Reporting

* **The server is authoritative on everything** — authorization, identity, workspace, draft state,
  baseline rules. These tools return its response *unchanged* by design. Quote it; do not paraphrase
  a refusal into your own words, and never soften one into "it may not have permission".
* **Say what is in the package**, from `cc_get_release_package` after the adds, not from the list you
  submitted — `autoInclude` is exactly the gap between the two.
* **A run has stages.** "Started" is one fact and "passed" is another; give the run id and the stage
  it is on rather than a single verdict.

## Do not

* Do not create a package to "see what happens". These are writes to a customer's release pipeline.
* Do not start a run the user did not ask for, and never as a way of testing that a package is valid.
* Do not retry a refused mutation with different arguments hoping it lands — a refusal names its
  reason, and working around it is the one thing this governed exception exists to prevent.
stress-test6.19 KB

View saved version →

---
name: stress-test
description: Author, revise, preview, publish, run, inspect, and stop CrossCheck Stress Tests against NetSuite. Use for load curves, traffic-volume experiments, Stress Test contracts, smoke/full runs, run progress, results, or cancellation. Agent execution is limited to verified sandbox or release_preview environments; hand production and development execution to the user in CrossCheck. Accepted runs are asynchronous with an immediate Run link. For regression assertions without load use test-suite; for writing application unit tests use neither.
---

# Stress Test — from workload intent to a live Run

The platform owns execution and evidence. You turn the user's workload into a reviewed contract,
then perform only the operations they requested. Authoring does not imply execution. Smoke writes
real NetSuite records too; neither mode cleans them up.

## Route the intent first

| Request | Route |
| --- | --- |
| Create or revise a contract | [Authoring](references/authoring.md): discover, resolve cases, draft, validate and preview, review, persist |
| Publish | Read the exact revision, review its digest and effect, publish |
| Run | [Operations](references/operations.md): verify sandbox/release_preview; hand production and development to the user in CrossCheck, otherwise review and start asynchronously |
| Progress or results | List runs if needed, then read status or bounded report; no mutation approval |
| Stop | Resolve one exact Run, request cancellation; explain acknowledgement versus completed stop |

Resolve `workspaceId` with `cc_workspaces` and the target environment with `cc_environments`.
Reuse an unambiguous selection already made in this conversation. Ask only when multiple candidates
remain; never choose the first match or invent identifiers. Use the same authorized workspace on
every related call. Do not copy a Run reference from a different workspace.

Before each logical mutation, summarize target, concrete change and effect once. If the user already
authorized that exact scope, proceed; otherwise ask once. Creating a contract never authorizes a run.
Ready + publish is one operation. An explicit stop request authorizes stopping the identified Run;
do not add another approval loop. Core authorization remains authoritative.

## Production and development execution belong to the user in CrossCheck

Before any start, retry or rerun, call `cc_environments` for the selected workspace and match the
exact environment ID. Only an explicitly returned `environmentType` of `sandbox`
or `release_preview`, with `isActive: true`, permits Agent execution. Names, account-ID patterns,
user assurances and the MCP server's own
deployment environment are not proof. Missing, conflicting or unknown classification means do not
start; resolve it first. Do not relabel an environment to make execution eligible.

For `production` or `development`, refuse both smoke and full starts even when the user approves or requests an
exception. Explain that they must open the Stress Test in CrossCheck and start the Run themselves
using the product's confirmation flow. Do not call another execution tool, delegate the start,
provide an executable API workaround, or click the product's Run controls on their behalf.
Do not substitute a different environment without the user's selection.

Authoring, validation, preview, publishing, status/report reads and an explicitly requested stop
remain available for production and development. No Run is created by the handoff, so do not invent a Run URL.
After the user starts it, resolve the actual Run and return its server-provided link. The MCP runtime
independently verifies fresh authorized environment metadata before every start
and rejects production, development or unverified targets before dispatch. This also applies to Test Suite and
CI workflow starts. Product UI execution remains available; the skill must not click Run for the user.
This gate takes precedence over retry guidance: if a start timed out and the refreshed type is
production, development or unknown, inspect existing Runs to reconcile acceptance without resending the start.
Keep the original idempotency key; an uncertain response never proves that no Run was created.

## Non-negotiable behavior

- Arrival rate is the default authoring model. Ask for traffic volume and duration; don't ask for
  concurrency unless the user explicitly needs a concurrent-worker experiment.
- Read `cc_stress_test_capabilities` before authoring. Flows reference published canonical Test Suite
  cases; no scripts, duplicated step language, guessed record IDs, or guessed unsupported actions.
- Preserve unrelated flows, pools, stages and tags when editing. Use the current definition digest
  for updates and the exact reviewed digest for publishing.
- Show whether variables come from supplied rows, generated values, or verified account reads.
  Generated business IDs are not verified IDs. Do not put secrets or credentials in data pools.
- Generate a unique idempotency key for each new mutation intent and retain it. Reuse it after a
  timeout or uncertain response; never turn a retry into a new run. Changed intent needs a new key.
- After start acceptance, immediately show the server's **runUrl** as a clickable link and identify
  environment, revision and smoke/full mode. Say "accepted" or the returned state, not "finished".
  End the response without waiting for completion. Poll only if the user asked you to watch; respect
  `suggestedPollAfterSeconds`, and still send the link before polling.
- Use returned **runUrl/resultUrl** verbatim. Never compose URLs from guessed slugs, internal IDs or
  the MCP host. If the server supplies no link, say it is unavailable and preserve the Run reference.
- A terminal Run may still be collecting its final report. Report these states separately. Missing
  account observations are unavailable/unobserved, not zero. There is no performance pass/fail verdict.
- Do not introduce schedules, automatic stops, thresholds, automatic cleanup, or extra backend
  approval fields. Do not silently lower, raise, or reinterpret a requested load curve.
- On a refusal, report the code and actionable paths/reasons. Read and repair a conflicting draft;
  do not overwrite or publish a newer definition under an older authorization.

Referenced files: 2

test-suite9.96 KB

View saved version →

---
name: test-suite
description: Author, register and run a CrossCheck Test Suite against a real NetSuite environment, from a user's need stated in prose (or from a checklist they hand you). Use whenever someone wants regression checks over a NetSuite account — "make sure the close still works", "check nothing broke after the release", "turn this QA checklist into something that runs". Produces a registered suite, a real run, and an explanation of what the account actually answered. NOT for writing test code; the runner executes a declared vocabulary, not scripts.
---

# Test Suite — from a need, to something that ran

Turn "make sure X still works" into a **registered Test Suite** that has **actually run against the
account**, and explain what came back.

> The platform owns execution and truth. You own the proposal. The one rule that makes this work at
> all: **you never invent an identifier.** Every script id, field id, saved search, role, list, file
> path and workflow you write into a suite must have come back `found` from the resolver.

## Why that rule is first

A previous author wrote a suite by guessing script ids that looked plausible. Every one of them
bounced when the account was asked. The account is the only thing that knows what is in it, and it
is one tool call away — so a guessed identifier is not a shortcut, it is a suite that cannot run.

## Method

### 1. Understand the need, and find the environment

Ask what breaking would look like, not what to test. "The close still works" becomes: the period can
close, the approval workflow is active, the report saved-search still returns rows.

Resolve workspace routing from `runtime_info`. With Cognito, call `cc_workspaces`. Use the sole
result automatically. If more than one is returned, ask the user to choose by safe name; never pick
the first or invent an id. Pass that discovered `workspaceId` to every CrossCheck tool. Then use
`cc_list_snapshots` / `cc_get_snapshot` to read what this environment actually contains before you
propose.

### 2. Learn what the runner can EXECUTE — not what the contract permits

**`cc_test_suite_capabilities` first, every time.** It returns the case kinds, the assertion kinds
allowed **per case kind**, the step actions, and the per-case assertion cap. The contract accepts
open codes; the RUNNER accepts this set. A suite that validates can still be refused at run time, so
author inside what this returns and nothing wider.

It also returns **`definitionEnvelope`** — the member names of a suite, a revision, a case, an
assertion and a cleanup policy, and which are optional. Build your draft from that. Do not discover
the shape by submitting drafts and reading `STRUCTURE_INVALID`: that refusal names the member and
then lists five things that might be wrong with it, so it costs one round trip per field and tells
you least when you know least.

Two things it will tell you that are easy to get wrong:

- assertion kinds are **per case kind**. `field_value` is a `data_integrity` assertion; sending it on
  a `schema_validation` case is refused locally as `assertion_kind`.
- the case's `targetRef` IS the subject for `schema_validation` and `data_integrity` (a record type),
  and names the FLOW for `functional` (each assertion there names its own subject). One case, one
  subject — two record types means two cases.

### 3. Propose in prose, then GROUND every identifier

Draft what you mean in words: "the approval workflow", "the customer credit-limit field", "the
open-orders saved search". Then hand every candidate to **`cc_resolve_test_suite_refs`** with the
environment, and use **only what comes back `found`**.

```jsonc
{ "environment": "env_…", "refs": [
  { "ref": "wf",     "kind": "workflow",    "scriptId": "customworkflow_po_approval" },
  { "ref": "search", "kind": "savedsearch", "scriptId": "customsearch_open_orders" },
  { "ref": "field",  "kind": "field",       "recordType": "customer", "fieldId": "creditlimit" }
] }
```

`absent` means propose something else or tell the user that thing is not in this environment. It does
NOT mean "try it and see" — the run would spend a live call to learn what you already know.

`found` means present **in the snapshot named in the response**, not necessarily present now. If the
snapshot is old, say so rather than implying currency.

**When you need a VALUE and not just existence, read it — never register a check to learn it.**
`cc_live_read` runs a SELECT-only SuiteQL against the live account through the platform, so
"which period is open", "what is this field set to", "does this search return rows today" are one
read away. `cc_get_snapshot` answers the same questions as of the last capture.

A registered suite belongs to the customer. It appears in their list of what they check, it runs
when they run it, and one written to fail on purpose — an assertion aimed at a value you are trying
to discover, so the evidence prints it back — is a lie sitting in that list. **Do not do it, on any
auth path.** If a read is refused, say what you could not see and let the person decide, rather than
turning the harness into a query tool.

### 4. Write assertions that can FAIL

This is where a suite is usually weak, and the weakness is invisible: a check that cannot fail
reports a pass forever.

- **`suitelet_responds` REQUIRES a body predicate.** NetSuite answers HTTP 200 with its LOGIN PAGE
  for a Suitelet whose deployment is not "Available Without Login", so `expectedStatus: 200` alone is
  satisfied by the one outcome the assertion exists to catch. The rail refuses status-only here
  (`endpoint_body_predicate_required`).
- **`restlet_responds` should assert the body too.** A 200 carrying `{"success": false}` is a
  failure wearing a success's status code. Use `bodyMatch: {kind: "json_subset", …}`, and send a real
  `method` + `body` when the endpoint takes one.
- **Negatives exist — use them.** `bodyMatch` has `not_contains` and `not_json_subset`; the
  `field_compare` assertion carries `not_equals`, `not_contains`, the four numeric comparisons,
  `is_empty` / `is_not_empty` and `is_true` / `is_false`. "This deprecated field is gone" and "the
  status is not Closed" are the checks a regression suite is actually for.
- `field_value` is equality only, and stays that way. Reach for `field_compare` when you need an
  operator.

### 5. Ask before you write

**`cc_validate_test_suite_definition`** runs the real writer with the commit removed and answers
`accepted` | `refused` | `conflict`. Nothing is registered.

- `refused` lists EVERY violation with its path — fix them in one pass, do not re-submit per error.
- `conflict` means the refs are taken AND the rest of the definition was acceptable. Those are two
  different repairs and the writer's own 409 cannot tell them apart.

Only once it says `accepted` do you call **`cc_create_test_suite`**. The two take the **same
payload** — `{suite, revision}` — so `accepted` is a statement about the call you are about to make,
not about a near neighbour of it.

If the register call answers 409, one of the refs is taken. If the SUITE already exists, that is not
a naming problem: go to step 7 and add a revision. Registering the same suite under a new `suiteRef`
throws away every run it has ever done.

If this tool answers `Route not found`, the environment you are talking to predates the dry run.
Register directly — and **say that you could not validate first**. Reporting "validated" against a
route that does not exist is the exact class of false claim this skill spends its length preventing.

### 6. Run it, and read what the account said

**`cc_start_test_suite_run`**, then `cc_get_test_suite` with the environment until the run is
terminal. Then explain, per case:

- `passed` / `failed` — the account answered and the assertion held or did not.
- `unsupported` — the runner refused the case locally; the reason token says why. It is **not** a
  failure of the account, and it is **not** a pass.
- `unknown` — the call was attempted and taught the run nothing. Never round this to either side.
- `skipped` — provably unattempted.

**Never report a pass that did not happen.** A check that could not run is `unknown`, and a suite
whose every case is `unsupported` is a suite that never tested anything, however green it looks.

### 7. Correcting a suite — a NEW REVISION, never a new suite

A suite that already exists is corrected by **adding a revision to it**, so it keeps its ref, its
name and its whole run history:

**`cc_get_test_suite_revision` first** — it returns the current revision IN FULL, with every case
and assertion. `cc_get_test_suite` gives you only the ref, ordinal and status, and an append
REPLACES nothing: whatever you leave out of the new revision is gone from what runs. Read it, change
the case that is wrong, send the rest back unchanged.

Then `cc_validate_test_suite_revision` → then `cc_add_test_suite_revision`.

`revisionOrdinal` must be **strictly greater** than the current newest — read it from
`cc_get_test_suite`. A stale or duplicate ordinal is refused naming that field, because the ordinal
is what "latest" means and two revisions claiming one number make it a coin flip.

Never register a corrected suite under a new `suiteRef`. That abandons every run the old one ever
did, and the history is the reason anyone trusts the suite.

## One limit worth telling the user about

**A run belongs to a (revision, environment) chain.** History is partitioned that way, so "this
suite's runs" always means one revision's runs in one environment — and the runner executes the
CURRENT revision or refuses (`manifest_drift`), never a superseded one.

## What this skill is NOT

- Not a way to write test code. The runner executes a declared vocabulary; if the need cannot be
  expressed in what `cc_test_suite_capabilities` returns, say that instead of approximating it.
- Not a mutation surface by default. A revision that declares mutating steps needs the mutating
  scope and writes to a real account — never propose one without saying, in the user's own terms,
  what it will create there and how it is cleaned up.
Package details

Publisher declarations from the archived package. These are separate from our research and the live service's terms.

Package author
Vertical Bar Inc

Package observed Oct 2, 2026.

Technical details
First seen
Sep 30, 2026 · 22:02 UTC
Last seen
Oct 2, 2026 · 06:00 UTC
Collection status
Collected

plugin_asdk_app_6a9b8a78c3b881919a1bffad07113bfb

Download plugin data (JSON)