Skip to content

Add /_skill-validation monitoring endpoint#5472

Merged
backspace merged 10 commits into
mainfrom
skill-validation-cs-11093
Jul 14, 2026
Merged

Add /_skill-validation monitoring endpoint#5472
backspace merged 10 commits into
mainfrom
skill-validation-cs-11093

Conversation

@backspace

@backspace backspace commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

In an early step of the @cardstack/base migration, the AI assistant was broken because skills imports had changed and there was no test suite failure, it’s more of an integration question.

This adds an endpoint that Checkly can poll, it reports whether each loaded skill’s tools load properly.

With this branch deployed to staging:

{
  "data": {
    "type": "skill-validation",
    "id": "https://realms-staging.stack.cards/skills/",
    "attributes": {
      "status": "pass",
      "skillsChecked": 41,
      "toolsChecked": 48,
      "failures": []
    }
  }
}

The corresponding Checkly check passed when it was deployed:

s 2026-07-13 at 13 05 10@2x

Here’s an example response with failures:

  {
    "data": {
      "type": "skill-validation",
      "id": "https://app.boxel.ai/skills/",
      "attributes": {
        "status": "fail",
        "skillsChecked": 12,
        "toolsChecked": 31,
        "failures": [
          {
            "skill": "https://app.boxel.ai/skills/Skill/boxel-development",
            "module": "@cardstack/boxel-host/commands/patch-card",
            "name": "default",
            "error": "encountered error loading module \"@cardstack/boxel-host/commands/patch-card\":
  404: Not Found"
          },
          {
            "skill": "https://app.boxel.ai/skills/writing-assistant.md",
            "module": "https://app.boxel.ai/skills/tools/rewrite",
            "name": "RewriteTool",
            "error": "module https://app.boxel.ai/skills/tools/rewrite has no export \"RewriteTool\""
          }
        ]
      }
    }
  }

backspace and others added 2 commits July 10, 2026 16:10
monitoringAuthToken is async, but handle-queue-status interpolated the
un-awaited Promise into its comparison string, so /_queue-status
actually authorized the literal token "[object Promise]" (and the test
passed because it interpolated the same Promise client-side). Move the
comparison into utils/monitoring.ts as isAuthorizedToViewMonitoring and
await the token on both sides.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Validates that every skill in a realm still resolves: enumerates Skill
cards via the index, imports each unique command codeRef module through
the prerenderer (a real host in headless Chrome, with the same shims
and virtual network a user's browser has), and returns structured
pass/fail per skill with the failing module path. Motivated by the
CS-10992/CS-11046 staging incident where a renamed host command path
silently broke the AI assistant while API health checks stayed green.

The module prerender response now carries all export names (not just
BaseDef definitions) so the endpoint can also catch a renamed export
whose module still loads.

Authenticated with the monitoring bearer token, same as /_queue-status.
A Checkly check in cardstack/infra will poll this per environment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Preview deployments

Host Test Results

    1 files  ±0      1 suites  ±0   3h 3m 23s ⏱️ +57s
3 486 tests ±0  3 471 ✅ ±0  15 💤 ±0  0 ❌ ±0 
3 505 runs  ±0  3 490 ✅ ±0  15 💤 ±0  0 ❌ ±0 

Results for commit fc85798. ± Comparison against earlier commit 8b2e697.

Realm Server Test Results

    1 files  ±0      1 suites  ±0   11m 42s ⏱️ +18s
1 829 tests ±0  1 829 ✅ +2  0 💤 ±0  0 ❌  - 2 
1 908 runs  ±0  1 908 ✅ +2  0 💤 ±0  0 ❌  - 2 

Results for commit fc85798. ± Comparison against earlier commit 8b2e697.

backspace and others added 2 commits July 10, 2026 16:24
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drop the CS-11093 tracker references and the staging-incident narrative
from the handler and route comments; state the threat model as the live
invariant instead. Rename the failure-reporting test timelessly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@backspace backspace changed the title Add /_skill-validation monitoring endpoint (CS-11093) Add /_skill-validation monitoring endpoint Jul 13, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5c28187b96

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/realm-server/handlers/handle-skill-validation.ts Outdated
Comment thread packages/realm-server/handlers/handle-skill-validation.ts
backspace and others added 3 commits July 13, 2026 14:58
Permission rows are keyed by full Matrix user id, so fetching them with
the bare username returned empty permissions and the prerender ran
anonymously — private realms reported module auth failures for valid
skills. Use the owner's user id and ensure owner permissions on the
target realm, matching the indexer's render path. The healthy-skills
test now runs against an owner-only realm to cover this.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A skill is either a legacy Skill card or a markdown file with
boxel.kind: skill frontmatter, whose frontmatter.tools carries the same
ToolField codeRefs as Skill.commands. The endpoint only searched Skill
card instances, so a realm with broken markdown-skill tool modules
reported pass. Query kind: 'skill' file entries via searchFiles and feed
their tool refs through the same prerender validation, reading the
legacy frontmatter.commands key when a pre-rename index row has no
tools value (mirroring the host's getSkillSourceTools fallback).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The platform renamed skill-attached "commands" to "tools" to align
with the agentic programming model, so this new endpoint's response
reports toolsChecked rather than baking the deprecated term into
monitoring consumers. Internal names and test fixtures follow; the
Skill card's pre-rename commands field and the legacy frontmatter
commands key keep their serialized spellings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@backspace backspace changed the title Add /_skill-validation monitoring endpoint Add /_skill-validation monitoring endpoint Jul 13, 2026
@backspace backspace requested a review from a team July 13, 2026 22:32
@habdelra habdelra requested a review from Copilot July 14, 2026 00:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new realm-server monitoring endpoint (/_skill-validation) that Checkly can poll to verify that all skills in a realm reference tool modules/exports that the deployed host can actually load (via the prerenderer), preventing “silent” integration breakages (e.g. module renames / export renames) that won’t show up as unit-test failures.

Changes:

  • Introduces /_skill-validation realm-server route + handler that finds skill sources (legacy Skill cards + skill-markdown files) and validates referenced tool codeRefs by prerendering unique modules and checking export names.
  • Extends the module prerender/model response contract with an optional exports?: string[] list, and populates it in the host /module route.
  • Refactors monitoring auth into a shared async helper (isAuthorizedToViewMonitoring) and adds comprehensive realm-server endpoint tests for both failure and success cases.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/runtime-common/index.ts Adds optional exports?: string[] to ModulePrerenderModel/ModuleRenderResponse contract for non-BaseDef export validation.
packages/runtime-common/constants.ts Adds markdownDefRef to query for MarkdownDef file rows (skill-markdown discovery).
packages/realm-server/utils/monitoring.ts Adds shared async isAuthorizedToViewMonitoring() used by monitoring endpoints.
packages/realm-server/handlers/handle-queue-status.ts Switches to shared async monitoring auth helper (fixes token comparison correctness with async token derivation).
packages/realm-server/routes.ts Registers new /_skill-validation endpoint.
packages/realm-server/handlers/handle-skill-validation.ts Implements the monitoring endpoint: skill discovery + prerender-based module/export validation + JSON:API response.
packages/realm-server/tests/server-endpoints/skill-validation-test.ts New tests covering auth requirements, bad params, module-load failures, missing-export failures, and private-realm success.
packages/realm-server/tests/server-endpoints/queue-status-test.ts Fixes test to await the async monitoring token.
packages/realm-server/tests/index.ts Adds the new skill-validation test file to the test suite.
packages/host/app/routes/module.ts Adds exports: Object.keys(module) to ready module models so prerender responses can report export names.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

backspace and others added 2 commits July 14, 2026 07:21
The skill-validation endpoint found markdown skills with a
searchFiles({ on: MarkdownDef, eq: { kind: 'skill' } }) query. The
eq filter makes the query resolve MarkdownDef's field definition, and
when that lookup misses the search engine swallows the error into an
empty result set — so every markdown skill was silently dropped and the
endpoint under-reported its skill/tool counts. Switch to a type-only
file search (which matches the indexed types column and needs no field
definition) and narrow to kind: 'skill' in JS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@backspace backspace merged commit dd692ea into main Jul 14, 2026
71 of 73 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants