Commit Graph
3 Commits
Author SHA1 Message Date
Hermes 9f9aeff0ab [pending-judge] feat(DC-165 rev2): product/site uniformity — fleet gate proven at composition root, single-source capabilities manifest
Site-vs-product audit (2026-10-09, owner decisions: "advertise as Premium"
and "It should be LLM readable") reconciles the entitlement triangle:
marketing copy <-> PREMIUM_FEATURES <-> license-server grant list.

r1 judge blockers/polish addressed:
- B2 (synthetic-router tests): NEW e2e fleet-gate-composition.e2e.test.js
  boots the REAL createApp() on an ephemeral port with a stdin control
  channel to mutate the live LicenseManager instance returned by createApp,
  proving: no activation -> 403 premiumRequired feature=fleet
  currentTier=free; activation WITHOUT fleet -> still 403 (per-feature,
  not tier-only); activation WITH fleet -> gate cleared; prefix inheritance
  across /fleet/hosts, /fleet/status, /fleet/deploy (4 real-boot tests).
- B0 (hand-typed constants in the manifest): MCP transport identity moved
  to MCP_RUNTIME in routes/mcp.js (the transport implementation's own
  module), exported; /info responses use MCP_RUNTIME.transport, and
  capabilities.js reads transport/protocolVersion/protocolVersions from
  the SAME object — nothing re-typed. New assertion: manifest == MCP_RUNTIME.
- B1 (OpenAPI 401 on a public route): capabilities block documents only
  200 with an explicit public-route note.
- P0 (migration replaced the whole array): now APPEND-ONLY union — current
  PREMIUM_FEATURES first, unknown legacy entries preserved verbatim.
  Dedicated test pins shape + persistence.
- P1 (eslint exit suppressed): verifier [5] hard-asserts rc==0.
- P2 (brief counts): brief quotes exact `git diff --stat` (below).

Product behavior:
- 'fleet' in PREMIUM_FEATURES; requirePremium('fleet') mounted at the
  /fleet ROUTER prefix in app.js BEFORE fleetRoutes -> every sub-route,
  present and future, inherits the gate.
- 'workflows' + 'auto-backup' (gated in routes forever, missing from the
  constant — offline grants could never include them) listed with
  descriptions quoted from src/recipes/bundled-workflows.js (5 ids) and
  routes/backups.js schedule schema (interval/retention/maxStorageBytes/
  destination/runImmediately). Manual one-click backup + Disaster Recovery
  stay free; only the schedule trio is gated (as coded).
- Offline activation forward-migration on load(); online untouched (server
  authoritative across the network boundary).
- GET /api/v1/capabilities: public ground truth derived from runtime
  modules only — APP_TEMPLATES, mcp-core TOOLS, mcp.js MCP_RUNTIME,
  PREMIUM_FEATURES, i18n, version.js. In PUBLIC_ROUTES (exact GET),
  covered by public-routes-drift directMounts; no-secrets negative test.
- openapi.yaml documents the endpoint.

diff --stat 4143bff..HEAD: 9 files, +558/-6:
  __tests__/dc165-uniformity.test.js        +201 (9 tests)
  __tests__/e2e-node/fleet-gate-composition +179 (4 real-boot tests)
  __tests__/public-routes-drift.test.js       +1
  openapi.yaml                               +20
  routes/capabilities.js                     +77 (NEW)
  routes/mcp.js                              +24/-4 (MCP_RUNTIME single source)
  src/app.js                                 +11 (fleet gate + capabilities mount)
  src/managers/license-manager.js            +50 (3 feature entries + migration)
  src/utilities/middleware.js                 +1 (PUBLIC_ROUTES)

Tests: 9 dc165 + 4 fleet-e2e + 76 license-manager + 21 tier-enforcement
+ 14 drift = 124 targeted; 73 MCP route/core tests unchanged green.
2026-10-09 02:28:52 -07:00
Hermes 73fde1e2a8 [grade=B] fix(DC-162 rev3): presence-based id detection, null-params rejection, boundary matrix
Judge r2 (grade C) — all 3 blockers + both polish items:

1. REQUEST-vs-NOTIFICATION by PRESENCE, never truthiness: validateJsonRpc
   uses hasOwnProperty('id'); id 0 and id '' are VALID request ids echoed
   back BY VALUE (strict-equality tested), id:null treated as a request
   under the documented error-id convention. mcp-core default branch fixed
   the same way (`if (id)` → hasOwnProperty — id 0 / '' unknown-method now
   answer -32601 with the id echoed instead of being swallowed as falsy).
   Routes' malformed-notification silence path also switched to
   presence-based detection (id:null + bad params → 400 envelope, not 204).

2. params:null REJECTED (-32600): contract is object-or-omitted ONLY
   (strict JSON-RPC; the old code's m.params !== null guard contradicted
   the documented contract). Boundary tests pin the policy.

3. Unknown-method boundary tests: id 0 → -32601 id:0, id '' → -32601 id:'',
   id null → -32601 id:null — asserted at BOTH layer levels (route).

Polish:
- 16-case TABLE-DRIVEN boundary matrix covering every allowed/rejected
  id/params combination incl. 202 vs 204 notification split.
- Verifier now probes writable /tmp up front (exit 73 + clear message if
  unavailable; documented requirement) instead of dying at mktemp.
- Verifier target count 57 → 73 (DC-162 suites) with the boundary table
  named in the assertion label.

Full DC-162 suite: 73 passed (route 50 + core 23). No transport/credential
semantics changed from rev2.

urn:ump:or2qqhcytp6lfzlyi7xru7hdqy3uar2hbjllsrrbxrbray3c5kpa
2026-10-08 04:02:26 -07:00
Hermes c9015b59ad [pending-judge] feat(DC-162 rev2): "Connect your AI" — spec Streamable HTTP MCP + one-click keys
Judge r1 (grade D) blockers, each fixed and tested:

1. TRANSPORT: custom POST-only JSON-RPC → MCP 2025-03-10 Streamable HTTP
   (spec-canonical; replaced HTTP+SSE). POST answers application/json for
   requests; valid notifications -> 202 empty; malformed notifications ->
   no reply (204); batching removed in this revision -> arrays rejected
   -32600. GET (server->client stream) and DELETE (session termination)
   answer 405 + Allow: POST — the spec's explicit allowance for stateless
   request/response servers; documented in /info + modal + OpenAPI.
   Origin header validated when present (DNS-rebinding MUST); Accept
   negotiation (json required, else 406); MCP-Protocol-Version header
   checked when sent. Clients needing server-initiated streams use the
   stdio bridge (unchanged, shares mcp-core).

2. CREDENTIAL TYPE PRESERVATION: routes/mcp.js now forwards the SAME
   scheme the caller authenticated with (req.auth.type from
   middleware.js:549-586): apikey -> x-api-key, jwt -> Authorization
   Bearer (NOT dk_-coerced-x-api-key as r1 did). mcp-core createToolHandler
   accepts explicit headers. Tests assert BOTH shapes downstream
   (apikey carries x-api-key & no Authorization; jwt carries Bearer & no
   x-api-key; zero downstream calls for session denial).

3. JSON-RPC VALIDATION: validateJsonRpc — jsonrpc:'2.0', non-empty string
   method, params object-or-omitted, id string|number|null. Invalid
   Request -32600 (empty body, empty array, batch); tools/call without
   string params.name -> -32602; unknown method -> -32601; error envelopes
   carry id null when unpairable. Transport primitives rejected by the
   app-wide strict JSON parser (400; asserted).

4. REPRODUCIBILITY: status/dist/features.js + sw.js regenerated and
   committed IN THE PATCH (repo convention: DC-130/131 committed bundle
   rebuilds). Verifier greps the built bundle for aiconn- (23),
   mcp/connections (1), httpConfig (2) so a clean `git am` checkout serves
   the real frontend.

Judge r1 polish, all applied:
- verifier accepts 0_PATCH.diff / PATCH.diff naming (indexed artifact);
- connections list filtered server-side to "AI connection (...)" keys
  (new GET /mcp/connections, session-only; modal switched to it);
- URL-encoded tool path params (serviceId, containerId, action,
  templateId, category, zone) in mcp-core.

Config shape: POST /mcp/config (session-only; apikey 403) returns the
standard Streamable-HTTP card {url, transport: streamable-http, headers:
{x-api-key}, mcpProtocolVersion} + per-client note (ChatGPT note states
the public-https requirement honestly; no fabricated connector claims).

Tests: 57 green (34 route incl. auth matrix/type-preservation/transport
rules/JSON-RPC errors + 23 core). Composition-root e2e (8) boots the real
createApp with the mount. eslint 0 errors. Full suite: only the
pre-existing pdf-parse billing family red (unchanged since base 470dfaa).
2026-10-08 03:46:56 -07:00