← Vertical Bar AgentCONTENT HISTORY

Update to Vertical Bar Agent

Snapshot Sep 30, 2026 · 23:07 UTC · version 0.13.8

Collection source: not recorded for this historical snapshot.

WHAT CHANGED · RULE-BASED ANALYSIS

First saved snapshot

No earlier snapshot is available to establish a change.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "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.",
  "included_files": [],
  "skill_md_contents": "---\nname: test-suite\ndescription: 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.\n---\n\n# Test Suite — from a need, to something that ran\n\nTurn \"make sure X still works\" into a **registered Test Suite** that has **actually run against the\naccount**, and explain what came back.\n\n> The platform owns execution and truth. You own the proposal. The one rule that makes this work at\n> all: **you never invent an identifier.** Every script id, field id, saved search, role, list, file\n> path and workflow you write into a suite must have come back `found` from the resolver.\n\n## Why that rule is first\n\nA previous author wrote a suite by guessing script ids that looked plausible. Every one of them\nbounced when the account was asked. The account is the only thing that knows what is in it, and it\nis one tool call away — so a guessed identifier is not a shortcut, it is a suite that cannot run.\n\n## Method\n\n### 1. Understand the need, and find the environment\n\nAsk what breaking would look like, not what to test. \"The close still works\" becomes: the period can\nclose, the approval workflow is active, the report saved-search still returns rows.\n\nResolve workspace routing from `runtime_info`. With Cognito, call `cc_workspaces`. Use the sole\nresult automatically. If more than one is returned, ask the user to choose by safe name; never pick\nthe first or invent an id. Pass that discovered `workspaceId` to every CrossCheck tool. Then use\n`cc_list_snapshots` / `cc_get_snapshot` to read what this environment actually contains before you\npropose.\n\n### 2. Learn what the runner can EXECUTE — not what the contract permits\n\n**`cc_test_suite_capabilities` first, every time.** It returns the case kinds, the assertion kinds\nallowed **per case kind**, the step actions, and the per-case assertion cap. The contract accepts\nopen codes; the RUNNER accepts this set. A suite that validates can still be refused at run time, so\nauthor inside what this returns and nothing wider.\n\nIt also returns **`definitionEnvelope`** — the member names of a suite, a revision, a case, an\nassertion and a cleanup policy, and which are optional. Build your draft from that. Do not discover\nthe shape by submitting drafts and reading `STRUCTURE_INVALID`: that refusal names the member and\nthen lists five things that might be wrong with it, so it costs one round trip per field and tells\nyou least when you know least.\n\nTwo things it will tell you that are easy to get wrong:\n\n- assertion kinds are **per case kind**. `field_value` is a `data_integrity` assertion; sending it on\n  a `schema_validation` case is refused locally as `assertion_kind`.\n- the case's `targetRef` IS the subject for `schema_validation` and `data_integrity` (a record type),\n  and names the FLOW for `functional` (each assertion there names its own subject). One case, one\n  subject — two record types means two cases.\n\n### 3. Propose in prose, then GROUND every identifier\n\nDraft what you mean in words: \"the approval workflow\", \"the customer credit-limit field\", \"the\nopen-orders saved search\". Then hand every candidate to **`cc_resolve_test_suite_refs`** with the\nenvironment, and use **only what comes back `found`**.\n\n```jsonc\n{ \"environment\": \"env_…\", \"refs\": [\n  { \"ref\": \"wf\",     \"kind\": \"workflow\",    \"scriptId\": \"customworkflow_po_approval\" },\n  { \"ref\": \"search\", \"kind\": \"savedsearch\", \"scriptId\": \"customsearch_open_orders\" },\n  { \"ref\": \"field\",  \"kind\": \"field\",       \"recordType\": \"customer\", \"fieldId\": \"creditlimit\" }\n] }\n```\n\n`absent` means propose something else or tell the user that thing is not in this environment. It does\nNOT mean \"try it and see\" — the run would spend a live call to learn what you already know.\n\n`found` means present **in the snapshot named in the response**, not necessarily present now. If the\nsnapshot is old, say so rather than implying currency.\n\n**When you need a VALUE and not just existence, read it — never register a check to learn it.**\n`cc_live_read` runs a SELECT-only SuiteQL against the live account through the platform, so\n\"which period is open\", \"what is this field set to\", \"does this search return rows today\" are one\nread away. `cc_get_snapshot` answers the same questions as of the last capture.\n\nA registered suite belongs to the customer. It appears in their list of what they check, it runs\nwhen they run it, and one written to fail on purpose — an assertion aimed at a value you are trying\nto discover, so the evidence prints it back — is a lie sitting in that list. **Do not do it, on any\nauth path.** If a read is refused, say what you could not see and let the person decide, rather than\nturning the harness into a query tool.\n\n### 4. Write assertions that can FAIL\n\nThis is where a suite is usually weak, and the weakness is invisible: a check that cannot fail\nreports a pass forever.\n\n- **`suitelet_responds` REQUIRES a body predicate.** NetSuite answers HTTP 200 with its LOGIN PAGE\n  for a Suitelet whose deployment is not \"Available Without Login\", so `expectedStatus: 200` alone is\n  satisfied by the one outcome the assertion exists to catch. The rail refuses status-only here\n  (`endpoint_body_predicate_required`).\n- **`restlet_responds` should assert the body too.** A 200 carrying `{\"success\": false}` is a\n  failure wearing a success's status code. Use `bodyMatch: {kind: \"json_subset\", …}`, and send a real\n  `method` + `body` when the endpoint takes one.\n- **Negatives exist — use them.** `bodyMatch` has `not_contains` and `not_json_subset`; the\n  `field_compare` assertion carries `not_equals`, `not_contains`, the four numeric comparisons,\n  `is_empty` / `is_not_empty` and `is_true` / `is_false`. \"This deprecated field is gone\" and \"the\n  status is not Closed\" are the checks a regression suite is actually for.\n- `field_value` is equality only, and stays that way. Reach for `field_compare` when you need an\n  operator.\n\n### 5. Ask before you write\n\n**`cc_validate_test_suite_definition`** runs the real writer with the commit removed and answers\n`accepted` | `refused` | `conflict`. Nothing is registered.\n\n- `refused` lists EVERY violation with its path — fix them in one pass, do not re-submit per error.\n- `conflict` means the refs are taken AND the rest of the definition was acceptable. Those are two\n  different repairs and the writer's own 409 cannot tell them apart.\n\nOnly once it says `accepted` do you call **`cc_create_test_suite`**. The two take the **same\npayload** — `{suite, revision}` — so `accepted` is a statement about the call you are about to make,\nnot about a near neighbour of it.\n\nIf the register call answers 409, one of the refs is taken. If the SUITE already exists, that is not\na naming problem: go to step 7 and add a revision. Registering the same suite under a new `suiteRef`\nthrows away every run it has ever done.\n\nIf this tool answers `Route not found`, the environment you are talking to predates the dry run.\nRegister directly — and **say that you could not validate first**. Reporting \"validated\" against a\nroute that does not exist is the exact class of false claim this skill spends its length preventing.\n\n### 6. Run it, and read what the account said\n\n**`cc_start_test_suite_run`**, then `cc_get_test_suite` with the environment until the run is\nterminal. Then explain, per case:\n\n- `passed` / `failed` — the account answered and the assertion held or did not.\n- `unsupported` — the runner refused the case locally; the reason token says why. It is **not** a\n  failure of the account, and it is **not** a pass.\n- `unknown` — the call was attempted and taught the run nothing. Never round this to either side.\n- `skipped` — provably unattempted.\n\n**Never report a pass that did not happen.** A check that could not run is `unknown`, and a suite\nwhose every case is `unsupported` is a suite that never tested anything, however green it looks.\n\n### 7. Correcting a suite — a NEW REVISION, never a new suite\n\nA suite that already exists is corrected by **adding a revision to it**, so it keeps its ref, its\nname and its whole run history:\n\n**`cc_get_test_suite_revision` first** — it returns the current revision IN FULL, with every case\nand assertion. `cc_get_test_suite` gives you only the ref, ordinal and status, and an append\nREPLACES nothing: whatever you leave out of the new revision is gone from what runs. Read it, change\nthe case that is wrong, send the rest back unchanged.\n\nThen `cc_validate_test_suite_revision` → then `cc_add_test_suite_revision`.\n\n`revisionOrdinal` must be **strictly greater** than the current newest — read it from\n`cc_get_test_suite`. A stale or duplicate ordinal is refused naming that field, because the ordinal\nis what \"latest\" means and two revisions claiming one number make it a coin flip.\n\nNever register a corrected suite under a new `suiteRef`. That abandons every run the old one ever\ndid, and the history is the reason anyone trusts the suite.\n\n## One limit worth telling the user about\n\n**A run belongs to a (revision, environment) chain.** History is partitioned that way, so \"this\nsuite's runs\" always means one revision's runs in one environment — and the runner executes the\nCURRENT revision or refuses (`manifest_drift`), never a superseded one.\n\n## What this skill is NOT\n\n- Not a way to write test code. The runner executes a declared vocabulary; if the need cannot be\n  expressed in what `cc_test_suite_capabilities` returns, say that instead of approximating it.\n- Not a mutation surface by default. A revision that declares mutating steps needs the mutating\n  scope and writes to a real account — never propose one without saying, in the user's own terms,\n  what it will create there and how it is cleaned up.\n"
}

SHA-256: fa3b96450d145128e9e4be9985690ee99f74da2af385e91bff83282463492f56