AI Wikis / Agentic Web

Carcinus Discovery and Contract Upgrade Report

Report summary

Carcinus already has several unusually strong foundations for an AI-facing platform: an official agent discovery document at /.well-known/ai-agent.json, an OpenAPI document at /.well-known/openapi.json, a public health endpoint, a machine-readable templates endpoint, a public changelog and status pa

Status
Research archive item
Category
AI Wikis / Agentic Web
Length
4,491 words
Reading time
21 minutes
Report type
evaluation

Key topics

  • AI Wikis / Agentic Web
  • AI Wikis
  • Agentic Web
  • AI
  • SEO
  • .NET
  • Runtime
  • Semantic Systems
  • Research Archive

Research provenance

Archive status
Research archive item
Content identity
sha256:9021eef35b1f69ecf96deb17ff8abccf39e1d121258bc47320c0a66c62062287

For citation, use the report title and canonical URL. Archival presence does not establish authorship or promote report statements into portfolio evidence.

Source availability: 73 citation markers in the source export have no recoverable source links. Those markers are omitted from this reader; any supplied bibliography and ordinary links remain. Check the original sources before relying on the cited claims.

This page renders the archived Markdown as safe, formatted HTML. It is background research and does not become a portfolio claim without evidence review.

Full report

On this page

Executive Summary

Carcinus already has several unusually strong foundations for an AI-facing platform: an official agent discovery document at /.well-known/ai-agent.json, an OpenAPI document at /.well-known/openapi.json, a public health endpoint, a machine-readable templates endpoint, a public changelog and status page, and multiple no-JavaScript meeting fallbacks such as /meetings/open and per-meeting text views. The OpenAPI document already declares application/problem+json for typed errors and an X-Correlation-Id header, which is exactly the right direction for reliable agent integrations.

The main problem is not lack of surface area; it is contract drift across official surfaces. The reviewed official sources disagree on core routes for site mutation, bot registration, temporary token flows, and meeting stats. At the same time, production indexes currently expose smoke artifacts, E2E artifacts, and test meetings in public discovery surfaces, while key core pages still depend on JavaScript and degrade to Loading... states. Discovery itself is partially unstable in practice: the docs say /llms.txt is the primary discovery endpoint, but the official links to /llms.txt and /llms-full.txt failed in this review browser.

The highest-risk defect is credential flow design. Carcinus currently documents one-time write tokens, optional email at registration, public temporary token issuance via GET /api/v2/tokens/request?agent=..., and multiple token-bearing GET flows in discovery metadata. That combination raises leakage, replay, accidental invocation, logging, cache, and browser-history risks. The second highest-risk defect is public-surface hygiene: test pages and rate-limit smoke meetings are visible in public indexes, which weakens trust and contaminates discovery for both humans and agents.

The upgrade plan should therefore move in this order: freeze one canonical contract and generate all public docs/discovery files from it; eliminate token-in-query-string and GET mutation as canonical flows; split summary DTOs from detail DTOs; quarantine or unlist smoke/test artifacts from public surfaces; add no-JavaScript server-rendered fallbacks for key core pages; and build CI that continuously checks discovery files, public contract parity, typed error envelopes, and public hygiene. Carcinus already has the right bones. The work now is to bring the visible skin, the public nerves, and the internal skeleton into one grammar.

Scope and Source Basis

This review is grounded in live production pages and official on-site documentation reviewed on June 5–6, 2026, including the official Site Map, API Instructions, API Reference, API v2 Reference, AI Agent Integration Guide, Status page, Changelog, Terms page, discovery JSON, OpenAPI, health endpoint, public directory/dashboard pages, meeting surfaces, memory surfaces, and representative public pages.

Representative rendered pages reviewed included the AI Sites Directory, the bot/site dashboard, the meeting dashboard, the starter template page, the public Carcinus page at /public/carcinus/, the Meeting Hub, the agent memory page, and an example public agent profile page. These are useful because they show how the platform behaves at the human-facing edges rather than only in the JSON contract center.

For governance-sync analysis, I also used Carcinus’s own research/governance artifacts—not as proof of runtime capability, but as proof that the platform already values explicit boundary language, public claim management, content inventory, and accessibility governance. That is a strength. It also makes the current contract/version/count drift more visible, because the platform already claims a higher standard of public coherence.

One important limitation: /llms.txt and /llms-full.txt are explicitly advertised as discovery surfaces in official docs and the official site map, but the official links to those files failed in this review browser. I therefore treat those files as discovery surfaces that must be validated by CI rather than as fully trusted, empirically verified sources from this particular review environment.

Detailed Findings

Carcinus’s discovery posture is good in spirit and partly good in implementation. /.well-known/ai-agent.json exists and is rich: it advertises capabilities, auth hints, HMAC webhook signing, rate limits, recovery links, public profile bases, memory endpoints, and an OpenAPI link. /.well-known/openapi.json also exists and already exposes OpenAPI 3.0.3 metadata plus a typed-error convention centered on application/problem+json and X-Correlation-Id. That gives Carcinus the raw materials for a very strong agent contract.

The problem is that the official contract is not singular. The API Reference says site update is PUT /api/v2/sites/{siteId}, publish is POST /api/v2/sites/{siteId}/publish, and delete is DELETE /api/v2/sites/{siteId}. The API v2 Reference says update is PUT /api/v2/sites, publish is POST /api/v2/sites/publish, and delete is DELETE /api/v2/sites/{botName}. The AI agent discovery JSON advertises still another variant: GET https://carcinus.org/api/v2/sites/publish-via-get?.... The same drift appears in bot registration and meeting stats. In other words, Carcinus currently has several official maps for the same territory.

Token lifecycle is the sharpest edge. The platform documents that POST /api/v2/bots returns a write token once, cannot recover it through the API, and falls back to email reset. Yet the dashboard presents contact email as optional, which implies that recovery can become impossible unless another recovery factor exists. The dashboard also invites users to paste a write token into the browser to load an existing bot, and the meeting start page offers a temporary token flow by slug. The actual temp-token endpoint returns a token and immediately suggests a next step that places that token in a query string. That is convenient DX, but poor credential hygiene.

The platform’s public surfaces are also more porous than they should be. The official site map lists 42 public bot pages, including /public/badbot/, /public/e2e-bot-20260604-0427/, and /public/live-smoke-get-mq0d2pq3/. The published-sites JSON includes smoke and E2E artifacts and currently exposes full htmlTemplate content for each listed site. The public meeting dashboard and open-meetings JSON similarly list active smoke meetings such as ProductionRateLimitSmoke, RateLimitHeaderSmoke, and other test titles. This is a trust problem, a discovery pollution problem, and a DTO minimization problem all at once.

AI-agent accessibility is best in the meeting surfaces and weaker in the core site-management surfaces. Meetings have a notable positive pattern: /meetings/dashboard offers text and JSON views, individual meeting rooms expose a no-JavaScript text view, and /meetings/open is agent-readable. By contrast, /sites, /memory, /meetings/archive, and /agents/TestAgent all degrade to Loading... or explicitly require JavaScript for their primary interactive experience. The no-JS bridge exists in some places, but it is not yet platform-wide.

Governance artifacts exist, but they are out of sync with each other and with runtime surfaces. The health endpoint reports version 3.1, runtime .NET 10.0.8, 62 total bots, and 42 published bots. The OpenAPI document says version 1.0, the agent discovery file says version 1.0, the docs speak in terms of API v2, and the changelog describes a “V1 public contract.” Meanwhile, the changelog’s platform stats list 39 published sites and 1084 unit tests; a research dashboard says there are 17 research pages; content health says 25; and the accessibility audit says 31 pages were audited. These are not just cosmetic mismatches—they are symptoms of a missing generation pipeline.

The official public governance language is actually a major opportunity. The Claim-Status Matrix requires every public claim to carry a status, evidence type, current support level, boundary language, and future handoff path. That same governance pattern should be applied to routes, discovery files, and documented capabilities. If Carcinus already knows how to govern claims, it can govern contracts with the same discipline.

SurfaceCurrent stateWhy it mattersRecommended action
/.well-known/ai-agent.jsonExists and advertises capabilities, auth hints, HMAC-signed webhooks, rate limits, recovery links, memory/message/relationship endpoints, and multiple GET fallbacks.Strong discovery surface, but it currently broadens the public contract beyond what the HTML docs consistently document.Generate it from the same manifest that generates OpenAPI and docs; add explicit stability, deprecated, and replacement fields per capability family.
/.well-known/openapi.jsonExists and declares OpenAPI 3.0.3 plus application/problem+json, route-level/controller-level error status coverage, and X-Correlation-Id.This should be the canonical machine contract.Make it the single source of truth for docs, SDK generation, CI parity tests, and discovery-file generation.
/llms.txtOfficial docs call it the primary discovery endpoint, and the official site map exposes it, but the official browser link failed with (400) OK in this review environment.Primary discovery cannot be “maybe reachable”; agents need it to be boring and stable.Enforce text/plain; charset=utf-8, strong caching headers, HEAD support, and CI curl validation.
/llms-full.txtOfficially advertised as the full technical reference, but the official browser link failed in this review environment.This undermines agent confidence in deep discovery.Same remediation as /llms.txt; also keep it generated from OpenAPI + manifest rather than hand-authored.
/sitemap.xmlOfficially exposed in the site map and SEO docs as part of discovery and indexing.Sitemap correctness matters for search discovery and agent crawling.Validate in CI for well-formed XML, freshness, and parity with public indexable pages.
/api rootGET /api/health is official, and /api/ai/* routes are documented, but no canonical /api root index is surfaced in the reviewed docs.Root discovery helps both humans and agents orient before choosing a contract surface.Return a small JSON index or a typed 404 with discovery links.
/api/v2 rootAPI v2 is documented, but no reviewed official page exposes a canonical /api/v2 index route.Version roots are where agents look for stable affordances.Add GET /api/v2 that returns links, supported media types, stability policy, and deprecated routes.
/api/v2/sites and /api/v2/sites/publishedRoutes are documented inconsistently, and /api/v2/sites/published currently returns full HTML templates for listed pages, including smoke/E2E content.This is the core contract-stability and DTO-hygiene issue.Freeze a canonical route set, split summary from detail DTOs, paginate, and exclude non-production artifacts from public lists.
/public/*Stable public pages exist, but public discovery currently includes badbot, E2E, and smoke pages.Public trust and discovery relevance are degraded by internal/test artifacts.Add visibility, environment, and indexable controls; production lists should exclude non-production artifacts by default.
/meetings/*Meetings are agent-friendly and have text fallbacks, but public open-meeting lists currently expose smoke/test titles, and official docs still promote state-changing GET flows.Great DX, but risky automation semantics and public-surface pollution.Keep read-friendly text views; move canonical mutation to POST-only flows; default anonymous meetings to unlisted.

Contract and UX Recommendations

The fastest path to stability is to define one canonical contract and make every other public surface derive from it. Concretely, Carcinus should treat the OpenAPI document as authoritative, move all hand-authored HTML route tables to generated content, and keep /.well-known/ai-agent.json, /llms.txt, /llms-full.txt, the status page’s monitored-route list, and public changelog route notes synchronized from the same manifest. That would eliminate the current disagreement among API Instructions, API Reference, API v2 Reference, discovery JSON, the status page, and public route catalogs.

CapabilityCurrent surfaced contractRecommended canonical contract
Bot registrationPOST /api/v2/bots is documented as the standard path, but the temp-token flow and discovery JSON also surface GET /api/v2/bots/register?botName=X&token=Y.Keep POST /api/v2/bots as the only canonical registration endpoint. Deprecate query-token registration entirely.
Bot lookupAPI Reference documents both GET /api/v2/bots/{botName} and GET /api/v2/bots/{botId}, which creates an ambiguous path shape.Use GET /api/v2/bots/by-name/{botName} and GET /api/v2/bots/{botId} or GET /api/v2/bots/by-id/{botId}.
Site create/update/publish/deleteOfficial sources disagree among PUT /api/v2/sites/{siteId}, PUT /api/v2/sites, POST /api/v2/sites/{siteId}/publish, POST /api/v2/sites/publish, DELETE /api/v2/sites/{siteId}, DELETE /api/v2/sites/{botName}, and GET /api/v2/sites/publish-via-get?....Canonicalize to POST /api/v2/sites, PATCH /api/v2/sites/{siteId}, POST /api/v2/sites/{siteId}/publish, POST /api/v2/sites/{siteId}/unpublish, DELETE /api/v2/sites/{siteId}.
Site list/detail DTOs/api/v2/sites/published currently exposes full template content and test artifacts in list output.GET /api/v2/sites?published=true should return a summary DTO only; GET /api/v2/sites/{siteId} returns detail; add paging, ETag, and fields= selection.
Temporary write accessGET /api/v2/tokens/request?agent=slug returns a temp token and a next step that embeds that token in a query string.Replace with POST /api/v2/bots/{botName}/token-exchange or POST /api/v2/tokens/exchange; return a short-lived access token or signed session, never a secret in the URL.
Meetings create/join/sendThe platform documents both POST and GET mutation flows, and the Start page explicitly tells agents “No POST needed.”Canonicalize all mutation to POST. Keep GET only for read-only text pages and signed one-time human convenience links if absolutely required.
Meeting statsAPI v2 Reference uses /api/v2/meetings/stats, while discovery JSON advertises /api/v2/stats.Pick one path—prefer /api/v2/meetings/stats—and deprecate the other with explicit replacement metadata.
Memory proposeDiscovery JSON and API docs surface both POST and GET-fallback write flows for memory proposals.Keep POST /api/ai/memory/propose only; if no-JS support is needed, use an HTML <form method="post">, not GET mutation.

Carcinus’s current baseline is simple write tokens, public reads, HMAC-signed webhooks, and a rate limit of 20 mutations per minute per IP with higher limits for recognized agent user agents. That is a useful start, but it conflates bootstrap, browser UX, and unattended automation. The clean design is a three-lane system: a bootstrap lane, a human-interactive lane, and an unattended-automation lane.

Control laneBest forGainsCostsRecommendation
One-time bootstrap secretFirst registration onlyVery low friction onboardingDangerous if pasted into chat, URLs, or browser historyKeep only for bootstrap; hash server-side and never show again after issuance
Short-lived access tokenBrowser dashboard and ad-hoc agent sessionsSafer than long-lived secrets; easy revocation and expiryRequires exchange endpoint and expiry handlingMake this the default for dashboard/browser workflows
HMAC-signed requestsUnattended agents, server-to-server jobs, CI/CD, enterprise automationsReplay protection, no bearer secret in logs, strong auditabilitySlightly heavier client implementationPreferred lane for high-trust automation
IP allowlistStatic agents or enterprise runners with stable egressStrong reduction in anonymous abuseWeak for dynamic clouds, residential agents, and developer laptopsOptional additive control, not the primary auth model

The token lifecycle should be redesigned around explicit recovery and secret minimization. Registration should require at least one recovery factor before the user can close the success modal: verified email, WebAuthn resident key, recovery-code pack, or an uploaded/public GPG or age key. If the caller provides a public key at registration, Carcinus should offer an immediately downloadable encrypted secret bundle and never ask the caller to paste the long-lived token into a browser again. The dashboard should exchange the bootstrap secret for a short-lived access token and keep browser persistence off by default. That closes the current gap created by “one-time secret,” “optional email,” and “load existing bot by write token” all being true at the same time.

The best no-JavaScript strategy is not GET mutation; it is server-rendered POST forms plus read-only text/JSON fallbacks. Carcinus already proves the value of this pattern in meetings. Extend it to /sites, /memory, /agents/{slug}, /meetings/archive, and /meetings/search, each with a server-rendered baseline and richer enhancement on top. That keeps the bridge open for agents, terminal workflows, accessibility tooling, and humans on constrained browsers.

A recommended problem-details envelope for all public HTTP errors is below. It preserves the current problem+json direction while making recovery and discovery explicit.

{
  "type": "https://carcinus.org/problems/validation-failed",
  "title": "Validation failed",
  "status": 422,
  "detail": "Field 'botName' must match ^[a-z0-9-]{3,64}$.",
  "instance": "/api/v2/bots",
  "code": "validation_failed",
  "correlationId": "01JX2P6PHNQY9Y6A1V3E2J5K8M",
  "timestampUtc": "2026-06-06T00:00:00Z",
  "errors": [
    {
      "field": "botName",
      "message": "Use lowercase letters, digits, and hyphens only."
    }
  ],
  "nextStep": "Fetch /.well-known/openapi.json and retry with a valid payload.",
  "discovery": {
    "aiAgent": "/.well-known/ai-agent.json",
    "openApi": "/.well-known/openapi.json",
    "llms": "/llms.txt"
  }
}

A recommended HMAC scheme for unattended writes is below. The message to sign should be: METHOD + "\n" + PATH + "\n" + CANONICAL_QUERY + "\n" + TIMESTAMP + "\n" + NONCE + "\n" + BODY_SHA256_BASE64. Reject timestamps outside a five-minute skew window and cache nonces for at least ten minutes to prevent replay.

POST /api/v2/sites/38cf3811-0c5a-48e1-a0e9-0ac445e93ea8/publish HTTP/1.1
Host: carcinus.org
Content-Type: application/json
X-Carcinus-Key-Id: bot_60fd6a70
X-Carcinus-Timestamp: 2026-06-06T00:00:00Z
X-Carcinus-Nonce: 4f9d9991-18ff-4ae5-9c78-5feff4a9e7cd
X-Carcinus-Content-SHA256: Cb7Qx4xQ4l8mW3QhD0F3z7Qm5JH8j2Y2v2WQq3jL6mY=
X-Carcinus-Signature: v1=R2mA8A0j4vV0a3Wn9s7m7g2z4Z8Z5t4W0n0m4b1v6QY=

A concise recommended list DTO for published sites is below. The key principle is that list routes should summarize, not serialize the world.

{
  "items": [
    {
      "siteId": "38cf3811-0c5a-48e1-a0e9-0ac445e93ea8",
      "botName": "carcinus",
      "title": "Carcinus",
      "description": "Digital webmaster familiar for carcinus.org",
      "publicUrl": "/public/carcinus/",
      "isPublished": true,
      "updatedUtc": "2026-06-05T03:25:12Z",
      "qualityScore": 87,
      "tags": ["infrastructure", "publishing", "automation"]
    }
  ],
  "page": 1,
  "pageSize": 20,
  "total": 42,
  "links": {
    "self": "/api/v2/sites?published=true&page=1&pageSize=20",
    "next": null
  }
}

The registration and recovery UX should also change materially. The current experience invites token loss and browser paste-in. The improved flow is:

StepUX change
Registration successShow the bootstrap secret once, but keep the dialog “hard to close” until the caller either downloads an encrypted secret file, copies it, or configures a recovery factor
Recovery setupRequire at least one recovery factor before completing onboarding; if none is chosen, make the user explicitly acknowledge that recovery may be impossible
Browser sign-inExchange the bootstrap secret immediately for a short-lived access token; keep long-lived secrets out of browser storage by default
Automation setupOffer an “automation credentials” panel that creates a key ID + HMAC secret pair and explains replay-safe signing
Error copyUse direct messages such as: “This bootstrap secret is shown only once. Save it now or add a recovery factor before closing.” and “This token expired. Request a new short-lived access token; do not retry the old link.”

Prioritized Remediation Roadmap

The current state warrants a phased upgrade, not a single rewrite. The sources already show useful building blocks—OpenAPI, discovery JSON, typed errors, meeting text views, status/changelog transparency—but the mutations, credentials, and public indexes need tightening first because they are the most failure-prone and the most externally visible.

gantt
    title Carcinus upgrade roadmap
    dateFormat  YYYY-MM-DD
    axisFormat  %b %d

    section Contract stabilization
    Freeze canonical route registry            :a1, 2026-06-08, 10d
    Generate docs from OpenAPI + manifest      :a2, after a1, 14d
    Publish deprecations and replacements      :a3, after a1, 14d

    section Credential redesign
    Remove token-bearing GET flows from docs   :b1, 2026-06-08, 7d
    Add token exchange and rotation            :b2, after b1, 14d
    Add recovery factors and encrypted export  :b3, after b2, 14d
    Add HMAC request signing lane              :b4, after b2, 14d

    section Public hygiene
    Hide smoke and E2E artifacts from indexes  :c1, 2026-06-08, 7d
    Split summary vs detail DTOs               :c2, after c1, 10d
    Add visibility and environment flags       :c3, after c1, 10d

    section Accessibility and no-JS
    Add server-rendered core fallbacks         :d1, 2026-06-15, 14d
    Replace Loading-only pages with snapshots  :d2, after d1, 10d

    section CI and governance
    Add discovery and parity smoke tests       :e1, 2026-06-08, 10d
    Add no-JS and hygiene regression tests     :e2, after e1, 10d
    Generate status/changelog/site counts      :e3, after a2, 14d

Phase one should be ruthless and narrow. Freeze the canonical route registry; deprecate token-bearing GET flows in docs even before code removal; hide smoke, E2E, and obviously internal artifacts from public indexes; and extend production monitoring to discovery files, public lists, and typed error responses. This phase is about stopping further entropy.

Phase two should harden credentials and DTOs. Add short-lived token exchange, rotate/revoke endpoints, structured recovery, HMAC for unattended writes, summary/detail DTO splits, and explicit visibility/environment rules for sites and meetings. This phase is about reducing both accidental damage and public noise.

Phase three should automate governance. Generate API docs, discovery files, monitored-route lists, platform counts, and public route inventories from one manifest. This phase is about making drift harder to create than consistency.

CI, Monitoring, Risk, and KPIs

Carcinus’s changelog reports 1084 unit tests, which is impressive, but the public status page currently says it monitors only two legacy site endpoints. That means the platform likely has substantially better code-level testing than production surface monitoring. For an agent platform, that gap matters: agents fail on public contract drift long before they care how many internal classes are unit-tested.

Test or monitorWhat it should assert
Discovery availability smoke/.well-known/ai-agent.json, /.well-known/openapi.json, /llms.txt, /llms-full.txt, /sitemap.xml, and /api/health all return a 200 with the expected content type
Discovery parity test/.well-known/ai-agent.json, OpenAPI, HTML docs, and /llms*.txt all agree on canonical route paths, auth requirements, and deprecation status
Typed error testA missing route and a validation failure both return application/problem+json, include X-Correlation-Id, and include discovery links
GET mutation regression testNo canonical secret-bearing or state-changing path remains on GET, except explicitly whitelisted signed one-time links
Public hygiene test/api/v2/sites?published=true and public directories contain no smoke, E2E, badbot, or internal-only artifacts
No-JS snapshot test/sites, /memory, /agents/{slug}, /meetings/archive, and /meetings/search all render useful server-side baseline content without JavaScript
DTO size testList endpoints stay under a defined payload budget and do not include full HTML/template source by default
Monitoring coverage testThe monitored-route list is generated and includes discovery, health, list APIs, no-JS meeting pages, and one representative public page
Version sync testPlatform version, OpenAPI version, discovery version, and changelog release metadata align according to a documented taxonomy
Rate-limit header testThrottled responses include Retry-After and/or RateLimit-* headers, and limits differ by lane as documented

A practical deploy-time smoke script is below. It emphasizes the load-bearing surfaces that matter most to agents and external clients.

#!/usr/bin/env bash
# contract-smoke.sh
# Verifies Carcinus discovery surfaces, core public APIs, and basic hygiene.

set -euo pipefail

BASE="${BASE:-https://carcinus.org}"

check_status() {
  local url="$1"
  local expected="$2"
  local status
  status="$(curl -sS -o /tmp/resp.out -w "%{http_code}" "$url")"
  if [[ "$status" != "$expected" ]]; then
    echo "FAIL: $url returned $status, expected $expected"
    cat /tmp/resp.out || true
    exit 1
  fi
  echo "OK:   $url -> $status"
}

check_content_type() {
  local url="$1"
  local expected="$2"
  local ct
  ct="$(curl -sSI "$url" | awk -F': ' 'tolower($1)=="content-type"{print tolower($2)}' | tr -d '\r')"
  if [[ "$ct" != *"$expected"* ]]; then
    echo "FAIL: $url content-type '$ct' does not contain '$expected'"
    exit 1
  fi
  echo "OK:   $url content-type contains '$expected'"
}

check_no_public_artifact_leak() {
  local url="$1"
  local body
  body="$(curl -sS "$url")"
  if echo "$body" | grep -Eiq 'smoke|e2e|badbot|ratelimitheadersmoke|productionratelimitsmoke'; then
    echo "FAIL: public listing contains internal/test artifacts"
    exit 1
  fi
  echo "OK:   public listing is free of obvious internal/test artifacts"
}

check_json_field() {
  local url="$1"
  local needle="$2"
  if ! curl -sS "$url" | grep -Fq "$needle"; then
    echo "FAIL: $url missing expected content: $needle"
    exit 1
  fi
  echo "OK:   $url contains $needle"
}

check_status "$BASE/.well-known/ai-agent.json" "200"
check_status "$BASE/.well-known/openapi.json" "200"
check_status "$BASE/llms.txt" "200"
check_status "$BASE/llms-full.txt" "200"
check_status "$BASE/sitemap.xml" "200"
check_status "$BASE/api/health" "200"
check_status "$BASE/api/v2/sites/published" "200"
check_status "$BASE/meetings/open" "200"

check_content_type "$BASE/.well-known/ai-agent.json" "application/json"
check_content_type "$BASE/.well-known/openapi.json" "application/json"
check_content_type "$BASE/llms.txt" "text/plain"
check_content_type "$BASE/llms-full.txt" "text/plain"
check_content_type "$BASE/sitemap.xml" "xml"

check_json_field "$BASE/.well-known/openapi.json" '"openapi":"3.'
check_json_field "$BASE/.well-known/openapi.json" '"application/problem+json"'
check_json_field "$BASE/.well-known/ai-agent.json" '"correlationHeader":"X-Correlation-Id"'
check_json_field "$BASE/api/health" '"status":"Healthy"'

check_no_public_artifact_leak "$BASE/api/v2/sites/published"

echo "All contract smoke checks passed."

The current risk profile is below.

RiskLikelihoodImpactEvidence
Credential leakage through URLs, logs, caches, or browser historyHighHighTemp token issuance is public via GET and returns a next step containing the token in the query string; discovery metadata also advertises token-bearing GET flows.
Agent failure from contract driftHighHighOfficial docs disagree on site update/publish/delete routes, bot lookup shapes, and stats routes.
Public trust erosion from internal artifact exposureHighMediumPublic site discovery and meeting lists currently expose smoke, E2E, badbot, and rate-limit test artifacts.
Discovery/file-fetch instability for agentsMediumHigh/llms.txt and /llms-full.txt are primary discovery surfaces in docs, but their official links failed in this review browser.
Core-page accessibility/no-JS regressionsMediumMediumMultiple key pages still render Loading... or require JavaScript for their main experience.
Governance drift causing operator confusion and stale assumptionsHighMediumVersion numbers and page/site counts diverge across health, discovery, changelog, and governance artifacts.

Recommended KPIs are below. The “current baseline” column is intentionally blunt; it makes drift visible and gives the roadmap something measurable to pull toward.

KPICurrent baselineTarget
Public contract parity scoreBelow target; official docs and discovery surfaces disagree on core routes.100% parity across OpenAPI, docs, discovery JSON, and llms*.txt
Discovery probe success rateUnresolved; llms official links failed in this review browser.99.9% 30-day success for /.well-known/*, llms*.txt, and sitemap.xml
Secret-in-URL countGreater than zero today.Zero canonical secret-bearing URLs
Canonical GET mutator countGreater than zero today.Zero canonical GET mutators
Public artifact hygieneInternal/test artifacts are publicly visible today.Zero public smoke/E2E/internal artifacts
No-JS core task completionMixed; meetings are stronger than sites/memory/profile pages.At least 95% completion for browse, read, join, and publish bootstrap flows
Monitoring coverageStatus page names only two legacy monitored API endpoints.All discovery files + top public APIs + representative /public/* and /meetings/* routes
Version-governance syncHealth, OpenAPI, discovery, changelog, and docs use multiple overlapping version axes.One documented taxonomy with automated consistency checks

Complete Issues Log

IDSeverityAreaIssueEvidenceRemediation
CX-01CriticalContract stabilityOfficial site-mutation contract is inconsistent across official sources.API Reference, API v2 Reference, and discovery JSON disagree on update/publish/delete routes.Freeze one canonical route set; generate all docs/discovery from OpenAPI + manifest; publish deprecation map.
CX-02HighContract stabilityBot lookup route is path-ambiguous.API Reference documents both /api/v2/bots/{botName} and /api/v2/bots/{botId}.Split name and ID lookups into distinct paths such as /by-name/{botName} and /by-id/{botId} or /{botId}.
CX-03CriticalToken lifecycleTemporary write access is exposed via GET and query-string next steps.GET /api/v2/tokens/request?agent=TestAgent returns a temp token and a query-string-based next step.Replace with POST token exchange; never place secrets in URLs; issue short-lived access tokens.
CX-04HighSecurity vs automationMultiple mutation or write-adjacent flows are promoted on GET.Discovery JSON advertises GET registration/publish/message/memory-propose fallbacks; Start Meeting page says “No POST needed.”Make POST canonical for all mutation; keep GET read-only; use POST HTML forms for no-JS support.
CX-05HighToken lifecycleOne-time write tokens are paired with optional recovery details and browser paste-in UX.One-time token docs, optional contact email, “Load Existing Bot by Write Token,” and email reset all coexist.Require at least one recovery factor; add rotate/revoke; replace browser paste-in with short-lived access exchange.
CX-06HighPublic surface hygieneProduction public discovery surfaces expose internal/test artifacts.Official site map lists badbot, E2E, and smoke pages; open meetings list smoke/rate-limit tests.Add environment, visibility, and indexable flags; exclude non-production artifacts from all public lists by default.
CX-07HighDTO minimizationPublic site list output leaks full template bodies in a list endpoint./api/v2/sites/published currently returns htmlTemplate and other detail fields in list output.Split summary and detail DTOs; paginate; add fields=; keep heavy content off list routes.
CX-08MediumDiscovery reliabilityPrimary llms discovery files are advertised but failed through official links in this review browser.Docs call /llms.txt primary; official link fetches failed here.Add CI curl checks, explicit MIME tests, ETag/Last-Modified, and fallback generation from the canonical manifest.
CX-09MediumAI-agent accessibilitySeveral core pages still require JavaScript or degrade to Loading..../sites, /memory, /meetings/archive, and /agents/TestAgent show loading/JS dependence.Add server-rendered baseline content and keep JSON/text fallbacks for agents.
CX-10MediumMonitoringPublic status monitoring references only two legacy site endpoints.Status names /api/sites/starter-template and /api/sites/published while current docs/health emphasize v2 routes.Generate monitored-route lists from the same route manifest as docs and discovery files.
CX-11MediumGovernance syncVersion numbers and public counts are inconsistent across official surfaces.Health is 3.1; OpenAPI is 1.0; discovery JSON is 1.0; docs say API v2; changelog says V1; counts diverge across pages.Define version taxonomy and generate counts from source data instead of hardcoding them.
CX-12MediumPublic surface scopeDiscovery JSON advertises a broader surface than the main docs consistently explain.Discovery JSON includes messages, relationships, exports, MCP server, and a different stats path than the docs.Add explicit capability families with stability/deprecation metadata; every advertised capability must exist in the canonical docs.
CX-13MediumMeeting securityInvitations are explicitly public and trust-based with no authentication.Meeting Invitations page says all invitations are public and trust-based with no auth required.Keep anonymous invites only for low-risk public rooms; add signed invite tokens for private or agent-trusted flows.
CX-14MediumMeeting hygieneAnonymous/public meeting creation defaults create visible noise in public lists.Start/Create pages promote instant no-sign-up meetings, and public lists show many disposable rooms.Default anonymous meetings to unlisted; require explicit opt-in to appear in public open-meeting indexes.
CX-15MediumContent negotiationMeeting creation via browser redirect and docs description are not fully aligned.Create Meeting page says the GET start flow “Returns JSON,” while browser usage redirected to an HTML meeting room.Make behavior explicit by content type and Accept header; document redirects and JSON separately.
CX-16LowPublic health hygieneGET /api/health exposes runtime fingerprint, route inventory, and exact counts.Health returns .NET 10.0.8, counts, and public route catalog.Split into a minimal public health summary and a more detailed authenticated diagnostics surface.
CX-17LowGovernance polishResearch governance pages prove strong discipline, but their inventories are hardcoded and drift.Dashboard Metrics, Content Health, and Accessibility pages publish different total-page counts and note they are not live/hardcoded.Generate governance inventories from the actual route/page manifest during build.
CX-18LowSupport coherencePublic support/contact identity is split across multiple pages and addresses.About page uses one operator email; terms and directory surfaces use a different support email.Publish one support identity model: operator contact, platform support, and security contact, each with a clear role.
CX-19LowSite-map hygieneThe official site map contains duplicate meeting links.Meeting Dashboard, Archive, Metrics, and Invitations are repeated in the Site Map.Generate site maps from a normalized page manifest with duplicate detection.
CX-20LowPolicy/stabilityTerms explicitly disclaim endpoint stability during beta.Terms say there is no guarantee that endpoints or features remain unchanged.Publish a versioning/deprecation policy with stability tiers: experimental, beta, stable, legacy.