{"id":13290,"plugin_id":"plugin_asdk_app_6a9b8a78c3b881919a1bffad07113bfb","kind":"skill","collection_source":null,"comparison_source":null,"observed_at":"2026-09-30T23:07:16.827Z","digest":"2e36786ff7ee3e098b55beb751d33115f9ceb8db09f53fb26f5102ad974c8eb6","against":null,"payload":{"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.","included_files":[],"skill_md_contents":"---\nname: briefing\ndescription: 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.\n---\n\n# Briefing — author & publish an analysis surface\n\nTurn 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`).\n\n**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.\n\n> 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.\n\n## Method — any analysis, any data\n\n0. **Inspect `runtime_info`, then resolve authorized scope.** On the hosted remote surface, the MCP\n   request already carries verified identity: do not look for `login`, a local browser, a token\n   cache, or a window. On an installed local surface, use `login` only when `runtime_info` reports\n   that Cognito identity is absent and the reported runtime supports login. In every case, discover\n   workspace scope with `cc_workspaces`; no environment value or remembered workspace is authority.\n1. **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**:\n   - the **live read proxy** (`/api/v1/live-read`) — SuiteQL-as-a-GET over live NetSuite, for fresh reads;\n   - 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\");\n   - CrossCheck read APIs (snapshots / customizations / dependencies / employees) and Vertical Bar process data via their read surfaces.\n   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.\n2. **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).\n3. **Assemble a grounded bundle** = `{ goal, account, generated_at, coverage{available,missing}, facts: {<key>:{value, unit?, provenance}}, series, findings }`.\n4. **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.\n5. **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.\n6. **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).\n\n### Data paths that enrich results (easy to miss)\n\n**Call `briefing_schema` FIRST — it is the runtime source of the specific data-path map** (which landed\ntable, which column, which cross-product join key) for the account you are analyzing. It returns\n`{ tables, joinGraph, dataPaths, detectors }`; wire the ones the goal needs (not a prescription). Keep\nthese path-shaped reminders in mind and let `briefing_schema` supply the exact table/column/key names:\n\n- **Actor ids are LANDED — don't default to a name-only join.** Resolve a process actor to a\n  CrossCheck employee reference-first (the landed actor/creator keys are in `briefing_schema.dataPaths`\n  → `actor-identity`); integrations resolve by name via `cc_employees`. A live `systemnote` read\n  (`cc_live_read`) is the narrow fallback ONLY for a not-yet-landed human status-changer.\n- **There is a 2nd cross-product bridge beyond the transaction id** — see `briefing_schema.joinGraph`.\n- **Landed close tables are environment-scoped** — group by environment for multi-env work\n  (subsidiary ≠ environment); `briefing_schema` gives the exact keying.\n- **`$` amounts are coverage-gated** — posting txns carry GL; non-posting Sales Orders have none.\n  State the gap; never invent a figure. (`briefing_schema.dataPaths` → `amount-coverage`.)\n- **Live-read is budget 1/NetSuite-account, fail-closed** — prefer landed data; never parallel-run\n  the same account.\n\n## Tools (the current agent MCP)\n\nThe installed plugin and hosted remote MCP expose the same workspace-explicit analysis tools. Call\n`runtime_info` instead of inferring which surface is active. **Reads are HTTP proxies the platform\nruns server-side; the skill never holds DB/NetSuite credentials and never issues SQL against a\ndatabase directly.**\n\n- **`login({ email?, password? })` — installed surfaces only.** If `runtime_info` reports a local\n  surface with no Cognito identity, no args opens browser OAuth; explicit email+password is the Node\n  SRP compatibility path. The hosted remote surface has verified request identity and deliberately\n  exposes no `login` or `logout`. `whoami` shows current auth and workspace routing mode.\n- **`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.\n- **`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.\n- **`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.\n- **`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).\n- **`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.\n- **`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).\n\n### Deployment tool pack (RND-2907)\n\nNine workspace-scoped tools cover the governed deployment walkthrough. Reads:\n`cc_list_ci_workflows`, `cc_get_ci_workflow`, `cc_get_env_snapshot_git_source`,\n`cc_list_release_packages`, `cc_get_release_package`, `cc_get_ci_workflow_run`. Mutations:\n`cc_create_release_package`, `cc_add_release_package_items`, `cc_start_ci_workflow_run`.\n\nAll nine use the same routing as the other CrossCheck tools: pass the `workspaceId` returned by\n`cc_workspaces`. A Cognito user must have the server-authorized scopes for each operation.\n\nEach mutation is a single direct server call — there is no client-side `confirm`/preflight; the\nserver enforces its own guards and its response (including any error) is surfaced verbatim. Start-run\nrequires an identified Cognito user. Demo order: establish identity only when `runtime_info` says the\ninstalled runtime needs it → resolve the snapshot Git source → create package →\nadd items → get package/closure → start run → poll run. The full start→observe flow (strict\nall-target Review, staged A→B) needs PR #833 in the target deployment; before that, start-run\nreturns `RUN_ENGINE_NOT_READY` (503). Approval is intentionally absent and stays in the web UI.\n\n**Scope discovery — do this FIRST, never hardcode a workspace.** Call **`cc_workspaces`** (and\n`whoami`) to enumerate the workspaces authorized by the Cognito identity. Use the sole result\nautomatically. If more than one is returned and the user's request does not already identify one,\nask the user to choose by safe name; never pick the first or guess. **Thread that returned\n`workspaceId` to BOTH every data tool AND `briefing_publish`** — analyze and publish into the same\nworkspace. No ambient workspace scope exists. Confirm the `workspace` the publish result echoes back\nmatches the target. A `WORKSPACE_SCOPE_REQUIRED` refusal means perform this discovery and retry the\noriginal tool once. Use **`cc_live_read`** (the governed proxy — rate-limited, audited, row-capped)\nfor live reads; it is the only live-NetSuite path.\n\n**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.\n\n## Example analyses (illustrative — NOT the skill's scope)\n\nThe method above is identical for every domain; these are just example detector sets a goal might use:\n\n- **Close health** — period-state lag/blitz, owner-identity-join (systemnote actor × `employees`), task rework, late-JE timing, GL trial-balance; + VB process where relevant.\n- **Order-to-cash** — VB process states/variants/durations/bottlenecks (the VB transaction-status field; see `briefing_schema`) + CC GL trial-balance.\n- **AR aging / spend / anomaly / config-impact / lineage / …** — pick the data + detectors the question demands.\n\nDomain-specific detector queries are **reference content**, never the skill's identity. Add new domains by adding data/detectors, not by forking the skill.\n\n## Acceptance — the human pixel gate (output-blind)\n\n1. 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).\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}