Repository navigation
refactor(frontend): remove phone-home and Autofix from the dashboard - #57
Conversation
Thinker is self-hosted only, so the inherited Manifest Cloud UI goes. The frontend leaves first so no screen breaks when #14/#15 drop the matching backend endpoints. - Billing/plans: delete PlanPicker, UpgradeSuccessModal, UsageLimitBanner, the /upgrade page, the Register ?step=plan picker, the plan stores, the plan-based range locks on the analytics pages, the plan-limit upgrade CTAs in the request views, the Account billing and usage-email sections, and the @better-auth/stripe client plugin and dependency. - API Bot: delete the banner, the sidebar card, the dithered ground, their stylesheet and the SVG asset. - GitHub stars: drop the header star button and its /api/v1/github call. - Free Models: delete the page, its route, its API client and the assets only it used. - Managed Gemini Free: drop the provider entry, icon alias, background /ensure provisioning call and the Calendly key URL. - Cloud branches: checkIsSelfHosted() is gone and every screen behaves as self-hosted (Local providers always listed, local logs copy, CLI login pinned to this host, discovery after signup and setup). Drop the Manifest Cloud origin mapping, the cloud email card, the VITE_MANIFEST_SELFHOSTED read and the Dockerfile ENV that set it. - Help: drop the Manifest Calendly booking link. - Remove the dead CSS for all of the above, update the tests and the inherited dev guide. Closes #12 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Thinker makes no outbound calls of its own, and Autofix depended on Manifest's hosted Phoenix service. The dashboard drops both before the backend modules go in #16 and #17. - Update check: VersionIndicator now only shows the build-time __MANIFEST_VERSION__ badge. It makes no request, shows no "new version" link to the manifest.build changelog and has no dismiss state. services/api/version.ts and its test are gone. - Discovery: delete the post-signup questionnaire (page, service, styles, route, tests) and the pending-discovery redirects in AuthGuard and GuestGuard. First-admin setup now lands on / (Overview), signup on /welcome, and social signup also goes to /welcome. A leftover manifest_discovery_pending_* key from an older build no longer redirects anyone. - Wingman: delete the dev drawer, wingman-dev-proxy.ts, the VITE_WINGMAN_* / __WINGMAN_URL__ / __DEV_MODE__ build constants, the App and Welcome mounts, the drawer CSS and the CONTRIBUTING section. - Autofix: delete AutofixKpiCards, SettingsAutofixSection, NotificationBell (it only nagged about inactive Autofix), the Autofix switch and Manifest Terms/Privacy line on harness creation (modal and Welcome), the autofix badges, trigger filter, Phoenix panels, sibling links and status labels in the Requests views, the "Autofixed attempts" connection card, the Doctor tooltip variant, the healed chart series, the autofix fields in services/api/*, the two public PNGs, and the dead CSS. - The generic reliability metrics that the backend still serves under the legacy /overview/autofix-* paths (success rate, fallback recoveries, request status over time, per harness/provider/model reliability) stay. They are now read through neutral clients (getReliabilityStats, getRequestStatusTimeseries, RELIABILITY_PATHS) and shown by ReliabilityKpiCards. "Self-healed" becomes "Recovered" and counts fallback recoveries only. - Update the tests, the design-system registry and the inherited dev guide. Closes #13 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Revisão: PR #57 (#13, remover phone-home e Autofix do dashboard)Escopo: Não há blocker. O veredito é Critério de alto risco que se aplica
1. Fluxo de auth: sem bypass e sem loop
2.
|
Review follow-up for #57. - A harness stored without autofix_enabled inherits the backend default. The backend turns Autofix ON when it detects no container (bare-metal npm start, dev runs), and the dashboard no longer has a switch to turn it off. Until #16 removes Autofix from the backend: - createAgent always sends autofix_enabled: false, which covers the Connect Harness modal, Welcome and ConnectProvider; - duplicateAgent follows the copy with PATCH /routing/:agent/autofix {enabled:false}, because the duplicate endpoint has no field for it. Both live in one commented block in services/api/agents.ts, with tests on the request payloads. - The request-status timeseries client folds a legacy `healed` key into `success`. The backend's success rate already counts those requests as successes, so the bars still sum to the request total, Success + Recovered + Error matches the Success rate card, and Recovered stays fallback-only, like its KPI. - The Requests page rewrites a stale ?trigger= value (for example ?trigger=autofix) on load to the filter it actually applies. - Add AuthGuard tests for /cli/auth, with and without a session. - Correct the dev guide: the self-hosted default is OFF only in a container or with MANIFEST_MODE=selfhosted. Document AUTOFIX_GLOBAL_ENABLED=false as the operator workaround for existing harnesses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-revisão: PR #57 (head dd0ad62)Escopo:
Li o código ao redor nesse SHA, inclusive os handlers do backend que o delta chama. Não há blocker. O should-fix e os nits da revisão anterior foram tratados. O veredito continua Delta verificado1. Opt-out do Autofix legado (
2. Dobra de
3. Reescrita do
4. Teste do Os dois casos estão cobertos: sem sessão, redireciona para 5. Guia e corpo do PR
Execuções locais neste SHA
No bundle:
AchadosBlockers: nenhum. Should-fix: nenhum aberto. Nits
Gates
Head revisado: dd0ad62 |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-revisão: PR #57 depois do merge do #51 (head 17f7d5b)Antes revisado: Atenção: o PR está fechado e o GitHub não vê este head
Topologia e equivalência
Código novo da
|
| Comando | Resultado |
|---|---|
npm ci |
passa |
build do shared |
passa |
tsc --noEmit do frontend |
passa |
eslint src/ |
0 erros, 49 warnings (as mesmas de antes) |
vite build |
passa |
TZ=UTC vitest run |
201 arquivos, 4180 testes passam |
shared jest |
23 suítes, 539 testes passam |
Bundle: não aparecem wingman, /api/v1/version, PostHog nem Sentry. Os hosts externos são só links clicáveis, como na revisão anterior.
Blockers
Nenhum no código. O gate de CI ainda não foi cumprido; ver acima.
Should-fix
Nenhum.
Nits
packages/backend/src/cors-csp-config.ts:159: o comentário aponta parapackages/frontend/wingman-dev-proxy.ts, que não existe mais. Atualize na limpeza do backend (Remover Autofix/Phoenix do backend #16).packages/backend/src/notifications/emails/doctor-release.tsx:37: o template morto referencia o asset apagado. Remova junto com o Autofix do backend (Remover Autofix/Phoenix do backend #16).- O nit 1 da revisão anterior (o toast do PATCH de opt-out no
duplicateAgent) continua opcional.
Risco alto
O critério de antes continua valendo. O PR muda os guards de sessão e os redirects pós-autenticação (components/AuthGuard.tsx, components/GuestGuard.tsx, pages/Setup.tsx, pages/Register.tsx). Isso entra em "muda auth: sessões". O merge é decisão do mantenedor (ADR 0002).
Gates
- CI: pendente. É preciso reabrir o PR e esperar a CI verde em
17f7d5b. qa-docker: precisa rodar de novo neste head. A árvore de runtime agora junta as remoções do PR com o código novo damain: headers do Playground (fix(playground): block credential headers in Playground extra headers #104/fix(frontend): warn on invalid Playground headers and stop storing values #106/fix(providers): make adapter headers win over Playground extra headers #107), servidores locais (fix(backend): route chat for built-in LM Studio and llama.cpp providers #100/fix(providers): reserve local runner aliases and validate their base URLs #103), x-api-key (feat(gateway): accept x-api-key as an agent key transport #63) e better-auth 1.7.7 (chore(deps): bump the better-auth group across 1 directory with 5 updates #5). Roteiro:- o da revisão anterior (criar e duplicar harness com
autofix_enabled=false; o HAR só com o host da instância); - o login, o setup e o registro;
- o Playground com headers extras.
- o da revisão anterior (criar e duplicar harness com
- Validade: o veredito vale só para o SHA abaixo.
Head revisado: 17f7d5b
Veredito: risco alto (aguardar mantenedor)
qa-docker: PASSTested SHA:
Egress comparison (PR vs main, same procedure)Outbound TCP SYNs from the app container to public addresses:
Nothing new was contacted during the idle period in either run. In the browser, the PR dashboard issues no Observations (not blockers, nothing flaky, nothing needed a retry):
|
Brings in 498de23 (main plus #60) so #16 can merge into main after #60. Conflicts came from #57's interim dashboard handling of the legacy Autofix backend overlapping with this branch's backend removal: - frontend analytics client: RELIABILITY_PATHS points at the neutral /overview/reliability/* routes. foldLegacyRecoveredKey is dropped: the backend computes the request disposition from success/fallback only and DropAutofixSchema removes requests.autofix_status, so no row can come back as "healed", and the dashboard ships with its own backend. - frontend agents client: the auto-merged autofix_enabled opt-out on create and the PATCH /routing/:agent/autofix after duplicate are dropped (the field and the endpoint no longer exist; create rejects the field). - shared: keep the playground-headers exports, drop the autofix-status ones. - tests: keep this branch's versions (neutral paths, no opt-out, no fold). - e2e specs from main (local providers, reserved local runner aliases): stop sending autofix_enabled on agent create. - manifest guide: keep the "Autofix removed" section and neutral-path wording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#66) * refactor(frontend): remove the SaaS layer from the dashboard Thinker is self-hosted only, so the inherited Manifest Cloud UI goes. The frontend leaves first so no screen breaks when #14/#15 drop the matching backend endpoints. - Billing/plans: delete PlanPicker, UpgradeSuccessModal, UsageLimitBanner, the /upgrade page, the Register ?step=plan picker, the plan stores, the plan-based range locks on the analytics pages, the plan-limit upgrade CTAs in the request views, the Account billing and usage-email sections, and the @better-auth/stripe client plugin and dependency. - API Bot: delete the banner, the sidebar card, the dithered ground, their stylesheet and the SVG asset. - GitHub stars: drop the header star button and its /api/v1/github call. - Free Models: delete the page, its route, its API client and the assets only it used. - Managed Gemini Free: drop the provider entry, icon alias, background /ensure provisioning call and the Calendly key URL. - Cloud branches: checkIsSelfHosted() is gone and every screen behaves as self-hosted (Local providers always listed, local logs copy, CLI login pinned to this host, discovery after signup and setup). Drop the Manifest Cloud origin mapping, the cloud email card, the VITE_MANIFEST_SELFHOSTED read and the Dockerfile ENV that set it. - Help: drop the Manifest Calendly booking link. - Remove the dead CSS for all of the above, update the tests and the inherited dev guide. Closes #12 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(backend): remove billing, Stripe and plan limits Billing, Stripe and the Free/Pro plans belong to the SaaS layer that Thinker drops (docs/decisoes-iniciais.md section 3). - Delete packages/backend/src/billing (PlanService, billing controller, billing emails, request quota window, subscription status) and drop BillingModule from the app, proxy and analytics modules. - Proxy: remove the per-request plan gate (assertWithinRequestLimit) and the PLAN_LIMIT_REQUESTS / M204 handling in the controller and the exception filter. The proxy no longer answers 402 on its own; a 402 follows the generic error path. - Auth: remove the @better-auth/stripe plugin; drop the stripe and @better-auth/stripe dependencies from the backend. - Recording retention: keep only the global path (365-day default or REQUEST_RECORDING_RETENTION_DAYS); per-plan retention is gone. - Tenant entity: drop limit_overrides and billing_email_preferences; delete the TenantRequestUsage entity. - Shared: delete plan-limits and its exports. - Remove the STRIPE_* / PLAN_LIMIT_* / PLAN_REQUEST_QUOTA_RESET_AT variables from .env.example. - New migration DropBillingSchema1803200000000 drops the quota trigger and function, requests.quota_counted, tenant_request_usage, billing_email_logs and the two tenant columns. The old AddTenantRequestUsage migration keeps only its self-hosted path (a no-op up) so it no longer imports deleted billing code. /api/v1/billing/* no longer exists, and the STRIPE_* and PLAN_LIMIT_* variables are ignored if set. Closes #14 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(frontend): remove phone-home and Autofix from the dashboard Thinker makes no outbound calls of its own, and Autofix depended on Manifest's hosted Phoenix service. The dashboard drops both before the backend modules go in #16 and #17. - Update check: VersionIndicator now only shows the build-time __MANIFEST_VERSION__ badge. It makes no request, shows no "new version" link to the manifest.build changelog and has no dismiss state. services/api/version.ts and its test are gone. - Discovery: delete the post-signup questionnaire (page, service, styles, route, tests) and the pending-discovery redirects in AuthGuard and GuestGuard. First-admin setup now lands on / (Overview), signup on /welcome, and social signup also goes to /welcome. A leftover manifest_discovery_pending_* key from an older build no longer redirects anyone. - Wingman: delete the dev drawer, wingman-dev-proxy.ts, the VITE_WINGMAN_* / __WINGMAN_URL__ / __DEV_MODE__ build constants, the App and Welcome mounts, the drawer CSS and the CONTRIBUTING section. - Autofix: delete AutofixKpiCards, SettingsAutofixSection, NotificationBell (it only nagged about inactive Autofix), the Autofix switch and Manifest Terms/Privacy line on harness creation (modal and Welcome), the autofix badges, trigger filter, Phoenix panels, sibling links and status labels in the Requests views, the "Autofixed attempts" connection card, the Doctor tooltip variant, the healed chart series, the autofix fields in services/api/*, the two public PNGs, and the dead CSS. - The generic reliability metrics that the backend still serves under the legacy /overview/autofix-* paths (success rate, fallback recoveries, request status over time, per harness/provider/model reliability) stay. They are now read through neutral clients (getReliabilityStats, getRequestStatusTimeseries, RELIABILITY_PATHS) and shown by ReliabilityKpiCards. "Self-healed" becomes "Recovered" and counts fallback recoveries only. - Update the tests, the design-system registry and the inherited dev guide. Closes #13 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(frontend): opt new harnesses out of legacy Autofix until #16 Review follow-up for #57. - A harness stored without autofix_enabled inherits the backend default. The backend turns Autofix ON when it detects no container (bare-metal npm start, dev runs), and the dashboard no longer has a switch to turn it off. Until #16 removes Autofix from the backend: - createAgent always sends autofix_enabled: false, which covers the Connect Harness modal, Welcome and ConnectProvider; - duplicateAgent follows the copy with PATCH /routing/:agent/autofix {enabled:false}, because the duplicate endpoint has no field for it. Both live in one commented block in services/api/agents.ts, with tests on the request payloads. - The request-status timeseries client folds a legacy `healed` key into `success`. The backend's success rate already counts those requests as successes, so the bars still sum to the request total, Success + Recovered + Error matches the Success rate card, and Recovered stays fallback-only, like its KPI. - The Requests page rewrites a stale ?trigger= value (for example ?trigger=autofix) on load to the filter it actually applies. - Add AuthGuard tests for /cli/auth, with and without a session. - Correct the dev guide: the self-hosted default is OFF only in a container or with MANIFEST_MODE=selfhosted. Document AUTOFIX_GLOBAL_ENABLED=false as the operator workaround for existing harnesses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(backend): remove waitlist, CRM, Gemini Free, free models, GitHub stars and error pages Remove the Manifest Cloud and marketing surfaces from the backend: - waitlist/ (pivot and Autofix claims) and its open-CORS pivot route (applyPivotClaimCors, PIVOT_CLAIM_PATH, PIVOT_CLAIM_CLOUD_ORIGIN). - crm-metrics/ and CRM_METRICS_SECRET. - The managed Gemini Free provider: routing/managed-free-provider/, common/constants/managed-free-providers.ts, the CREDITS_* variables, and its entries in provider-endpoints, provider-client, provider.service, provider-model-fetcher and routing.module. No other provider's endpoint, prefix handling, fallback order or tier resolution changes. - free-models/ (sync from mnfst/awesome-free-llm-apis), github/ (stars from api.github.com) and error-pages/ (public and Peacock push routes, seeders, discovery), MANIFEST_PUBLIC_STATS and ERROR_PAGE_PUSH_SECRET. - gemini-free and the managedFree flag from manifest-shared, and the regenerated CLI provider catalog. - The plan_request_limit_exceeded error class left over from #14. DropSaasFeatureSchema1803300000000 sets a transaction-local lock_timeout, drops waitlist_claims, public_error_pages and the cloud-only IDX_requests_autofix_healed index, and deletes every gemini-free connection with its agent grants. Request history keeps its provider label, and routes that still name gemini-free resolve as unavailable and fall through to their fallbacks, as after a disconnect. down() restores the two tables as the self-hosted path created them. Closes #15 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(backend)!: remove Autofix and the Phoenix healer from the backend Autofix sent failing requests to Manifest's hosted healer (autofix.manifest.build) and pinged it at every production boot. Thinker makes no such call (#16). The local self-heal of v0.6 will build on the fallback chain on its own terms. - Delete routing/autofix (AutofixService, healing clients, health probe, observation reporter, Phoenix types and vendored contract) and the contract:refresh script with its ajv/js-yaml devDependencies. - Proxy: drop the heal-once branch from the primary and fallback hops and the wire-body retry hook from ForwardResult. A failed request now goes straight to shouldTriggerFallback, exactly as for an agent that never opted in. The primary is always attempt 1, the x-manifest-provider / x-manifest-auth-type replay rewrite is gone, and the recorder writes no repair columns or auto_fixed rows. - Analytics: move the generic reliability metrics to /api/v1/overview/reliability/{stats,timeseries,per-agent,per-provider, per-model} without the Autofix fields; drop the healed disposition, the auto_fixed counter, the autofix trigger filter and the connection breakdown's Autofix attempts. - Remove /autofix/status, /autofix/enable-all, the per-harness /routing/:agent/autofix endpoints, the autofix_enabled create field, the MCP Autofix tools and the CLI `routing autofix` command and `--autofix`. - Schema: DropAutofixSchema1803400000000 drops the autofix columns, check constraint and indexes (lock_timeout, IF EXISTS, full revert). 1802200000000 now runs its self-hosted no-op path everywhere. - Shared: drop deriveAutofixStatus, AUTOFIX_STATUSES and auto_fixed. - Delete the unused doctor-release email. - Frontend: call the neutral reliability paths and drop the temporary autofix_enabled opt-out, the duplicate PATCH and the healed fold. - Docs: move the PoC spec to docs/referencia/, remove AUTOFIX_* from the guide, .env.example and the Docker README. BREAKING CHANGE: the Autofix API, analytics paths, MCP tools and CLI command are removed; the reliability analytics moved to /api/v1/overview/reliability/*. Closes #16 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the billing drop e2e through the database guard Refs #67 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the SaaS drop e2e through the database guard Refs #67 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the Autofix drop e2e through the database guard The DropAutofixSchema e2e spec opens its own DataSource with dropSchema, so it now takes its URL from resolveE2eDatabaseUrl() like the other migration specs instead of falling back to a default localhost database. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* refactor(frontend): remove the SaaS layer from the dashboard Thinker is self-hosted only, so the inherited Manifest Cloud UI goes. The frontend leaves first so no screen breaks when #14/#15 drop the matching backend endpoints. - Billing/plans: delete PlanPicker, UpgradeSuccessModal, UsageLimitBanner, the /upgrade page, the Register ?step=plan picker, the plan stores, the plan-based range locks on the analytics pages, the plan-limit upgrade CTAs in the request views, the Account billing and usage-email sections, and the @better-auth/stripe client plugin and dependency. - API Bot: delete the banner, the sidebar card, the dithered ground, their stylesheet and the SVG asset. - GitHub stars: drop the header star button and its /api/v1/github call. - Free Models: delete the page, its route, its API client and the assets only it used. - Managed Gemini Free: drop the provider entry, icon alias, background /ensure provisioning call and the Calendly key URL. - Cloud branches: checkIsSelfHosted() is gone and every screen behaves as self-hosted (Local providers always listed, local logs copy, CLI login pinned to this host, discovery after signup and setup). Drop the Manifest Cloud origin mapping, the cloud email card, the VITE_MANIFEST_SELFHOSTED read and the Dockerfile ENV that set it. - Help: drop the Manifest Calendly booking link. - Remove the dead CSS for all of the above, update the tests and the inherited dev guide. Closes #12 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(backend): remove billing, Stripe and plan limits Billing, Stripe and the Free/Pro plans belong to the SaaS layer that Thinker drops (docs/decisoes-iniciais.md section 3). - Delete packages/backend/src/billing (PlanService, billing controller, billing emails, request quota window, subscription status) and drop BillingModule from the app, proxy and analytics modules. - Proxy: remove the per-request plan gate (assertWithinRequestLimit) and the PLAN_LIMIT_REQUESTS / M204 handling in the controller and the exception filter. The proxy no longer answers 402 on its own; a 402 follows the generic error path. - Auth: remove the @better-auth/stripe plugin; drop the stripe and @better-auth/stripe dependencies from the backend. - Recording retention: keep only the global path (365-day default or REQUEST_RECORDING_RETENTION_DAYS); per-plan retention is gone. - Tenant entity: drop limit_overrides and billing_email_preferences; delete the TenantRequestUsage entity. - Shared: delete plan-limits and its exports. - Remove the STRIPE_* / PLAN_LIMIT_* / PLAN_REQUEST_QUOTA_RESET_AT variables from .env.example. - New migration DropBillingSchema1803200000000 drops the quota trigger and function, requests.quota_counted, tenant_request_usage, billing_email_logs and the two tenant columns. The old AddTenantRequestUsage migration keeps only its self-hosted path (a no-op up) so it no longer imports deleted billing code. /api/v1/billing/* no longer exists, and the STRIPE_* and PLAN_LIMIT_* variables are ignored if set. Closes #14 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(frontend): remove phone-home and Autofix from the dashboard Thinker makes no outbound calls of its own, and Autofix depended on Manifest's hosted Phoenix service. The dashboard drops both before the backend modules go in #16 and #17. - Update check: VersionIndicator now only shows the build-time __MANIFEST_VERSION__ badge. It makes no request, shows no "new version" link to the manifest.build changelog and has no dismiss state. services/api/version.ts and its test are gone. - Discovery: delete the post-signup questionnaire (page, service, styles, route, tests) and the pending-discovery redirects in AuthGuard and GuestGuard. First-admin setup now lands on / (Overview), signup on /welcome, and social signup also goes to /welcome. A leftover manifest_discovery_pending_* key from an older build no longer redirects anyone. - Wingman: delete the dev drawer, wingman-dev-proxy.ts, the VITE_WINGMAN_* / __WINGMAN_URL__ / __DEV_MODE__ build constants, the App and Welcome mounts, the drawer CSS and the CONTRIBUTING section. - Autofix: delete AutofixKpiCards, SettingsAutofixSection, NotificationBell (it only nagged about inactive Autofix), the Autofix switch and Manifest Terms/Privacy line on harness creation (modal and Welcome), the autofix badges, trigger filter, Phoenix panels, sibling links and status labels in the Requests views, the "Autofixed attempts" connection card, the Doctor tooltip variant, the healed chart series, the autofix fields in services/api/*, the two public PNGs, and the dead CSS. - The generic reliability metrics that the backend still serves under the legacy /overview/autofix-* paths (success rate, fallback recoveries, request status over time, per harness/provider/model reliability) stay. They are now read through neutral clients (getReliabilityStats, getRequestStatusTimeseries, RELIABILITY_PATHS) and shown by ReliabilityKpiCards. "Self-healed" becomes "Recovered" and counts fallback recoveries only. - Update the tests, the design-system registry and the inherited dev guide. Closes #13 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(frontend): opt new harnesses out of legacy Autofix until #16 Review follow-up for #57. - A harness stored without autofix_enabled inherits the backend default. The backend turns Autofix ON when it detects no container (bare-metal npm start, dev runs), and the dashboard no longer has a switch to turn it off. Until #16 removes Autofix from the backend: - createAgent always sends autofix_enabled: false, which covers the Connect Harness modal, Welcome and ConnectProvider; - duplicateAgent follows the copy with PATCH /routing/:agent/autofix {enabled:false}, because the duplicate endpoint has no field for it. Both live in one commented block in services/api/agents.ts, with tests on the request payloads. - The request-status timeseries client folds a legacy `healed` key into `success`. The backend's success rate already counts those requests as successes, so the bars still sum to the request total, Success + Recovered + Error matches the Success rate card, and Recovered stays fallback-only, like its KPI. - The Requests page rewrites a stale ?trigger= value (for example ?trigger=autofix) on load to the filter it actually applies. - Add AuthGuard tests for /cli/auth, with and without a session. - Correct the dev guide: the self-hosted default is OFF only in a container or with MANIFEST_MODE=selfhosted. Document AUTOFIX_GLOBAL_ENABLED=false as the operator workaround for existing harnesses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(backend): remove waitlist, CRM, Gemini Free, free models, GitHub stars and error pages Remove the Manifest Cloud and marketing surfaces from the backend: - waitlist/ (pivot and Autofix claims) and its open-CORS pivot route (applyPivotClaimCors, PIVOT_CLAIM_PATH, PIVOT_CLAIM_CLOUD_ORIGIN). - crm-metrics/ and CRM_METRICS_SECRET. - The managed Gemini Free provider: routing/managed-free-provider/, common/constants/managed-free-providers.ts, the CREDITS_* variables, and its entries in provider-endpoints, provider-client, provider.service, provider-model-fetcher and routing.module. No other provider's endpoint, prefix handling, fallback order or tier resolution changes. - free-models/ (sync from mnfst/awesome-free-llm-apis), github/ (stars from api.github.com) and error-pages/ (public and Peacock push routes, seeders, discovery), MANIFEST_PUBLIC_STATS and ERROR_PAGE_PUSH_SECRET. - gemini-free and the managedFree flag from manifest-shared, and the regenerated CLI provider catalog. - The plan_request_limit_exceeded error class left over from #14. DropSaasFeatureSchema1803300000000 sets a transaction-local lock_timeout, drops waitlist_claims, public_error_pages and the cloud-only IDX_requests_autofix_healed index, and deletes every gemini-free connection with its agent grants. Request history keeps its provider label, and routes that still name gemini-free resolve as unavailable and fall through to their fallbacks, as after a disconnect. down() restores the two tables as the self-hosted path created them. Closes #15 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(backend)!: remove Autofix and the Phoenix healer from the backend Autofix sent failing requests to Manifest's hosted healer (autofix.manifest.build) and pinged it at every production boot. Thinker makes no such call (#16). The local self-heal of v0.6 will build on the fallback chain on its own terms. - Delete routing/autofix (AutofixService, healing clients, health probe, observation reporter, Phoenix types and vendored contract) and the contract:refresh script with its ajv/js-yaml devDependencies. - Proxy: drop the heal-once branch from the primary and fallback hops and the wire-body retry hook from ForwardResult. A failed request now goes straight to shouldTriggerFallback, exactly as for an agent that never opted in. The primary is always attempt 1, the x-manifest-provider / x-manifest-auth-type replay rewrite is gone, and the recorder writes no repair columns or auto_fixed rows. - Analytics: move the generic reliability metrics to /api/v1/overview/reliability/{stats,timeseries,per-agent,per-provider, per-model} without the Autofix fields; drop the healed disposition, the auto_fixed counter, the autofix trigger filter and the connection breakdown's Autofix attempts. - Remove /autofix/status, /autofix/enable-all, the per-harness /routing/:agent/autofix endpoints, the autofix_enabled create field, the MCP Autofix tools and the CLI `routing autofix` command and `--autofix`. - Schema: DropAutofixSchema1803400000000 drops the autofix columns, check constraint and indexes (lock_timeout, IF EXISTS, full revert). 1802200000000 now runs its self-hosted no-op path everywhere. - Shared: drop deriveAutofixStatus, AUTOFIX_STATUSES and auto_fixed. - Delete the unused doctor-release email. - Frontend: call the neutral reliability paths and drop the temporary autofix_enabled opt-out, the duplicate PATCH and the healed fold. - Docs: move the PoC spec to docs/referencia/, remove AUTOFIX_* from the guide, .env.example and the Docker README. BREAKING CHANGE: the Autofix API, analytics paths, MCP tools and CLI command are removed; the reliability analytics moved to /api/v1/overview/reliability/*. Closes #16 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(backend)!: remove phone-home from the backend and the CLI Thinker makes no outbound call of its own. Remove every upstream phone-home from the backend and the CLI: - usage telemetry (telemetry/, InstallIdService, PayloadBuilderService, the InstallMetadata entity) and the CLI usage spool (packages/cli/src/telemetry.ts); - the daily update check (version/, GET /api/v1/version, the GitHub releases URL); - the discovery forwarding to blue.manifest.build (discovery/, POST /api/v1/discovery/complete); - Sentry (instrument.ts, sentry/, SentryModule/SentryGlobalFilter, the @sentry/nestjs dependency); - the hosted Wingman origin in CORS and CSP frame-src; frame-src is 'self' in every mode and WINGMAN_CORS_ORIGINS becomes THINKER_CORS_ORIGINS with the same meaning; - the modelparams.dev fetch on boot and hourly cron; parameter specs come only from the bundled modelparams package snapshot. DropInstallMetadata1803500000000 drops the install_metadata table (lock_timeout, IF EXISTS, revert recreates it empty). The removed variables leave docker-compose, the .env examples, the Docker README, the deploy templates and the developer guide. A new e2e guard fails if the backend, CLI or shared source names a removed destination again, or if a production-mode boot of the real server fetches or resolves anything outside the ADR 0003 catalogs. BREAKING CHANGE: GET /api/v1/version and POST /api/v1/discovery/complete are gone, the hosted Wingman origin is no longer allowed by CORS, and WINGMAN_CORS_ORIGINS is renamed THINKER_CORS_ORIGINS. Closes #17 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): default to a local gateway instead of Manifest Cloud With no --url, MANIFEST_URL or stored login, the CLI targeted https://app.manifest.build, so a MANIFEST_API_KEY set without a host went to Manifest's cloud. DEFAULT_URL is now http://localhost:2099, the default Thinker port, and the invalid-URL hint and README follow. The backend's 404 hint for /chat/completions told callers to point their baseURL at https://app.manifest.build/v1; it now refers to this gateway. The egress guard now fails on app.manifest.build or gateway.manifest.build anywhere in the CLI or shared source (tests included), on a new backend production file naming them, on a CLI default that is not local, and on a boot request to either host. The three remaining backend files (Cloud trusted origins, the dashboard link fallback and the OG-tag placeholder) are pinned for #18, #22 and #25 and may only shrink. Refs #17 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the billing drop e2e through the database guard Refs #67 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the SaaS drop e2e through the database guard Refs #67 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the Autofix drop e2e through the database guard The DropAutofixSchema e2e spec opens its own DataSource with dropSchema, so it now takes its URL from resolveE2eDatabaseUrl() like the other migration specs instead of falling back to a default localhost database. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the install-metadata drop e2e through the database guard The DropInstallMetadata migration spec and the no-phone-home egress spec both open a dropSchema connection. Resolve their URL with resolveE2eDatabaseUrl() from test/e2e-db-guard instead of falling back to localhost:5432, so neither can wipe a database that is not an explicit, disposable test database (#67, #69). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): escape host names fully in the egress spec patterns CodeQL flagged js/incomplete-sanitization: only dots were escaped before building a RegExp from the host constants. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* refactor(frontend): remove the SaaS layer from the dashboard Thinker is self-hosted only, so the inherited Manifest Cloud UI goes. The frontend leaves first so no screen breaks when #14/#15 drop the matching backend endpoints. - Billing/plans: delete PlanPicker, UpgradeSuccessModal, UsageLimitBanner, the /upgrade page, the Register ?step=plan picker, the plan stores, the plan-based range locks on the analytics pages, the plan-limit upgrade CTAs in the request views, the Account billing and usage-email sections, and the @better-auth/stripe client plugin and dependency. - API Bot: delete the banner, the sidebar card, the dithered ground, their stylesheet and the SVG asset. - GitHub stars: drop the header star button and its /api/v1/github call. - Free Models: delete the page, its route, its API client and the assets only it used. - Managed Gemini Free: drop the provider entry, icon alias, background /ensure provisioning call and the Calendly key URL. - Cloud branches: checkIsSelfHosted() is gone and every screen behaves as self-hosted (Local providers always listed, local logs copy, CLI login pinned to this host, discovery after signup and setup). Drop the Manifest Cloud origin mapping, the cloud email card, the VITE_MANIFEST_SELFHOSTED read and the Dockerfile ENV that set it. - Help: drop the Manifest Calendly booking link. - Remove the dead CSS for all of the above, update the tests and the inherited dev guide. Closes #12 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(backend): remove billing, Stripe and plan limits Billing, Stripe and the Free/Pro plans belong to the SaaS layer that Thinker drops (docs/decisoes-iniciais.md section 3). - Delete packages/backend/src/billing (PlanService, billing controller, billing emails, request quota window, subscription status) and drop BillingModule from the app, proxy and analytics modules. - Proxy: remove the per-request plan gate (assertWithinRequestLimit) and the PLAN_LIMIT_REQUESTS / M204 handling in the controller and the exception filter. The proxy no longer answers 402 on its own; a 402 follows the generic error path. - Auth: remove the @better-auth/stripe plugin; drop the stripe and @better-auth/stripe dependencies from the backend. - Recording retention: keep only the global path (365-day default or REQUEST_RECORDING_RETENTION_DAYS); per-plan retention is gone. - Tenant entity: drop limit_overrides and billing_email_preferences; delete the TenantRequestUsage entity. - Shared: delete plan-limits and its exports. - Remove the STRIPE_* / PLAN_LIMIT_* / PLAN_REQUEST_QUOTA_RESET_AT variables from .env.example. - New migration DropBillingSchema1803200000000 drops the quota trigger and function, requests.quota_counted, tenant_request_usage, billing_email_logs and the two tenant columns. The old AddTenantRequestUsage migration keeps only its self-hosted path (a no-op up) so it no longer imports deleted billing code. /api/v1/billing/* no longer exists, and the STRIPE_* and PLAN_LIMIT_* variables are ignored if set. Closes #14 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(frontend): remove phone-home and Autofix from the dashboard Thinker makes no outbound calls of its own, and Autofix depended on Manifest's hosted Phoenix service. The dashboard drops both before the backend modules go in #16 and #17. - Update check: VersionIndicator now only shows the build-time __MANIFEST_VERSION__ badge. It makes no request, shows no "new version" link to the manifest.build changelog and has no dismiss state. services/api/version.ts and its test are gone. - Discovery: delete the post-signup questionnaire (page, service, styles, route, tests) and the pending-discovery redirects in AuthGuard and GuestGuard. First-admin setup now lands on / (Overview), signup on /welcome, and social signup also goes to /welcome. A leftover manifest_discovery_pending_* key from an older build no longer redirects anyone. - Wingman: delete the dev drawer, wingman-dev-proxy.ts, the VITE_WINGMAN_* / __WINGMAN_URL__ / __DEV_MODE__ build constants, the App and Welcome mounts, the drawer CSS and the CONTRIBUTING section. - Autofix: delete AutofixKpiCards, SettingsAutofixSection, NotificationBell (it only nagged about inactive Autofix), the Autofix switch and Manifest Terms/Privacy line on harness creation (modal and Welcome), the autofix badges, trigger filter, Phoenix panels, sibling links and status labels in the Requests views, the "Autofixed attempts" connection card, the Doctor tooltip variant, the healed chart series, the autofix fields in services/api/*, the two public PNGs, and the dead CSS. - The generic reliability metrics that the backend still serves under the legacy /overview/autofix-* paths (success rate, fallback recoveries, request status over time, per harness/provider/model reliability) stay. They are now read through neutral clients (getReliabilityStats, getRequestStatusTimeseries, RELIABILITY_PATHS) and shown by ReliabilityKpiCards. "Self-healed" becomes "Recovered" and counts fallback recoveries only. - Update the tests, the design-system registry and the inherited dev guide. Closes #13 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(frontend): opt new harnesses out of legacy Autofix until #16 Review follow-up for #57. - A harness stored without autofix_enabled inherits the backend default. The backend turns Autofix ON when it detects no container (bare-metal npm start, dev runs), and the dashboard no longer has a switch to turn it off. Until #16 removes Autofix from the backend: - createAgent always sends autofix_enabled: false, which covers the Connect Harness modal, Welcome and ConnectProvider; - duplicateAgent follows the copy with PATCH /routing/:agent/autofix {enabled:false}, because the duplicate endpoint has no field for it. Both live in one commented block in services/api/agents.ts, with tests on the request payloads. - The request-status timeseries client folds a legacy `healed` key into `success`. The backend's success rate already counts those requests as successes, so the bars still sum to the request total, Success + Recovered + Error matches the Success rate card, and Recovered stays fallback-only, like its KPI. - The Requests page rewrites a stale ?trigger= value (for example ?trigger=autofix) on load to the filter it actually applies. - Add AuthGuard tests for /cli/auth, with and without a session. - Correct the dev guide: the self-hosted default is OFF only in a container or with MANIFEST_MODE=selfhosted. Document AUTOFIX_GLOBAL_ENABLED=false as the operator workaround for existing harnesses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(backend): remove waitlist, CRM, Gemini Free, free models, GitHub stars and error pages Remove the Manifest Cloud and marketing surfaces from the backend: - waitlist/ (pivot and Autofix claims) and its open-CORS pivot route (applyPivotClaimCors, PIVOT_CLAIM_PATH, PIVOT_CLAIM_CLOUD_ORIGIN). - crm-metrics/ and CRM_METRICS_SECRET. - The managed Gemini Free provider: routing/managed-free-provider/, common/constants/managed-free-providers.ts, the CREDITS_* variables, and its entries in provider-endpoints, provider-client, provider.service, provider-model-fetcher and routing.module. No other provider's endpoint, prefix handling, fallback order or tier resolution changes. - free-models/ (sync from mnfst/awesome-free-llm-apis), github/ (stars from api.github.com) and error-pages/ (public and Peacock push routes, seeders, discovery), MANIFEST_PUBLIC_STATS and ERROR_PAGE_PUSH_SECRET. - gemini-free and the managedFree flag from manifest-shared, and the regenerated CLI provider catalog. - The plan_request_limit_exceeded error class left over from #14. DropSaasFeatureSchema1803300000000 sets a transaction-local lock_timeout, drops waitlist_claims, public_error_pages and the cloud-only IDX_requests_autofix_healed index, and deletes every gemini-free connection with its agent grants. Request history keeps its provider label, and routes that still name gemini-free resolve as unavailable and fall through to their fallbacks, as after a disconnect. down() restores the two tables as the self-hosted path created them. Closes #15 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(backend)!: remove Autofix and the Phoenix healer from the backend Autofix sent failing requests to Manifest's hosted healer (autofix.manifest.build) and pinged it at every production boot. Thinker makes no such call (#16). The local self-heal of v0.6 will build on the fallback chain on its own terms. - Delete routing/autofix (AutofixService, healing clients, health probe, observation reporter, Phoenix types and vendored contract) and the contract:refresh script with its ajv/js-yaml devDependencies. - Proxy: drop the heal-once branch from the primary and fallback hops and the wire-body retry hook from ForwardResult. A failed request now goes straight to shouldTriggerFallback, exactly as for an agent that never opted in. The primary is always attempt 1, the x-manifest-provider / x-manifest-auth-type replay rewrite is gone, and the recorder writes no repair columns or auto_fixed rows. - Analytics: move the generic reliability metrics to /api/v1/overview/reliability/{stats,timeseries,per-agent,per-provider, per-model} without the Autofix fields; drop the healed disposition, the auto_fixed counter, the autofix trigger filter and the connection breakdown's Autofix attempts. - Remove /autofix/status, /autofix/enable-all, the per-harness /routing/:agent/autofix endpoints, the autofix_enabled create field, the MCP Autofix tools and the CLI `routing autofix` command and `--autofix`. - Schema: DropAutofixSchema1803400000000 drops the autofix columns, check constraint and indexes (lock_timeout, IF EXISTS, full revert). 1802200000000 now runs its self-hosted no-op path everywhere. - Shared: drop deriveAutofixStatus, AUTOFIX_STATUSES and auto_fixed. - Delete the unused doctor-release email. - Frontend: call the neutral reliability paths and drop the temporary autofix_enabled opt-out, the duplicate PATCH and the healed fold. - Docs: move the PoC spec to docs/referencia/, remove AUTOFIX_* from the guide, .env.example and the Docker README. BREAKING CHANGE: the Autofix API, analytics paths, MCP tools and CLI command are removed; the reliability analytics moved to /api/v1/overview/reliability/*. Closes #16 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(backend)!: remove phone-home from the backend and the CLI Thinker makes no outbound call of its own. Remove every upstream phone-home from the backend and the CLI: - usage telemetry (telemetry/, InstallIdService, PayloadBuilderService, the InstallMetadata entity) and the CLI usage spool (packages/cli/src/telemetry.ts); - the daily update check (version/, GET /api/v1/version, the GitHub releases URL); - the discovery forwarding to blue.manifest.build (discovery/, POST /api/v1/discovery/complete); - Sentry (instrument.ts, sentry/, SentryModule/SentryGlobalFilter, the @sentry/nestjs dependency); - the hosted Wingman origin in CORS and CSP frame-src; frame-src is 'self' in every mode and WINGMAN_CORS_ORIGINS becomes THINKER_CORS_ORIGINS with the same meaning; - the modelparams.dev fetch on boot and hourly cron; parameter specs come only from the bundled modelparams package snapshot. DropInstallMetadata1803500000000 drops the install_metadata table (lock_timeout, IF EXISTS, revert recreates it empty). The removed variables leave docker-compose, the .env examples, the Docker README, the deploy templates and the developer guide. A new e2e guard fails if the backend, CLI or shared source names a removed destination again, or if a production-mode boot of the real server fetches or resolves anything outside the ADR 0003 catalogs. BREAKING CHANGE: GET /api/v1/version and POST /api/v1/discovery/complete are gone, the hosted Wingman origin is no longer allowed by CORS, and WINGMAN_CORS_ORIGINS is renamed THINKER_CORS_ORIGINS. Closes #17 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): default to a local gateway instead of Manifest Cloud With no --url, MANIFEST_URL or stored login, the CLI targeted https://app.manifest.build, so a MANIFEST_API_KEY set without a host went to Manifest's cloud. DEFAULT_URL is now http://localhost:2099, the default Thinker port, and the invalid-URL hint and README follow. The backend's 404 hint for /chat/completions told callers to point their baseURL at https://app.manifest.build/v1; it now refers to this gateway. The egress guard now fails on app.manifest.build or gateway.manifest.build anywhere in the CLI or shared source (tests included), on a new backend production file naming them, on a CLI default that is not local, and on a boot request to either host. The three remaining backend files (Cloud trusted origins, the dashboard link fallback and the OG-tag placeholder) are pinned for #18, #22 and #25 and may only shrink. Refs #17 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(backend): single self-hosted mode, drop MANIFEST_MODE Thinker has one deployment mode. The backend no longer decides between "cloud" and "self-hosted" from MANIFEST_MODE or container markers (/.dockerenv, /run/.containerenv, KUBERNETES_SERVICE_HOST); it always keeps the former self-hosted behavior, on any runtime: - built-in local providers (Ollama, LM Studio, llama.cpp) are always available: the cloud-only filters, the M303 rejection and its error code are gone; - custom-provider URLs validate with allowPrivate: LAN, loopback and http:// destinations are a feature, http:// to a public host is still refused, and cloud metadata endpoints stay blocked (now also by name: metadata.google.internal, metadata.goog, metadata, instance-data); - request recordings fall back to the filesystem without S3 credentials; - the boot backfills always run on the app's DATABASE_URL connection; - GET /api/v1/setup/status drops isSelfHosted and always probes Ollama. The CIMD client_id fetch does NOT inherit the old self-hosted allowance: that URL comes from an unauthenticated MCP client, so it is public-only by default (DNS failure is an error), with THINKER_CIMD_ALLOW_PRIVATE=true as the opt-in for LAN-hosted clients. auth.instance.ts no longer trusts the Manifest Cloud hosts (app/gateway.manifest.build) as origins or MCP resources; MCP is bound to the canonical BETTER_AUTH_URL origin only, and the file leaves the no-phonehome allow-list. detect-self-hosted.ts becomes container-host.ts with only getContainerHostAlias(). Unit tests no longer depend on /.dockerenv. Closes #18 Closes #46 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(backend): pin custom-provider connections against DNS rebinding Review of #71 (S1): with allowPrivate now constant for custom providers, a DNS failure passed validatePublicUrl, and fetch then resolved the name again with no check. A hostile resolver could answer a public address (or fail) during validation and 169.254.169.254 at connect time, so the probe and the forward could reach cloud metadata. - New common/utils/ssrf-safe-fetch.ts: undici fetch with a shared Agent whose connect.lookup resolves once, refuses the connection when any answer is a metadata address, and hands the socket only validated addresses. Metadata literals and names are refused before any socket. A DNS failure fails the request. - The custom-provider probe and the provider-client forward for user-supplied endpoints (requiresSsrfRevalidation) use it. - validatePublicUrl treats a DNS failure as an error even with allowPrivate (a .invalid host is refused). - S2: block the AWS container credential endpoints 169.254.170.2 (ECS), 169.254.170.23 and fd00:ec2::23 (EKS Pod Identity). - N2: classify IMDS embedded in IPv6 (IPv4-compatible, NAT64 64:ff9b::/96, 6to4, Teredo) as metadata; IPv6 metadata matches any textual form. - undici 6.29.0 becomes a backend dependency (the root override already pins undici ^6); Node's built-in fetch cannot take a foreign Agent across Node versions, so undici's own fetch is used. Tests: unit specs for the lookup and the classifier, and an e2e where a hostname resolves to a public address at validation and to 169.254.169.254 at connect: the probe and the forward are refused and a listener standing in for the metadata address receives 0 connections (it receives them when pinning is removed). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the billing drop e2e through the database guard Refs #67 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the SaaS drop e2e through the database guard Refs #67 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the Autofix drop e2e through the database guard The DropAutofixSchema e2e spec opens its own DataSource with dropSchema, so it now takes its URL from resolveE2eDatabaseUrl() like the other migration specs instead of falling back to a default localhost database. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the install-metadata drop e2e through the database guard The DropInstallMetadata migration spec and the no-phone-home egress spec both open a dropSchema connection. Resolve their URL with resolveE2eDatabaseUrl() from test/e2e-db-guard instead of falling back to localhost:5432, so neither can wipe a database that is not an explicit, disposable test database (#67, #69). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): drop MANIFEST_MODE from local-runner specs and fix the local log flake - Remove the MANIFEST_MODE=selfhosted setup that #100, #103 and #104 added to provider-client.local-servers.spec.ts, local-providers.e2e-spec.ts, reserved-local-runner-aliases.e2e-spec.ts and playground-request-headers.e2e-spec.ts. There is one mode now, so the variable does nothing. - local-providers.e2e-spec.ts: "logs local requests under the canonical provider at zero cost" read rows[0] of every llama.cpp row for the agent, with no ORDER BY, while earlier tests also log llama.cpp requests and a row starts as `pending` before its usage lands. Tag the request with its own traceparent and wait for that one settled row. Closes that part of #101. - mcp-cimd-ssrf.e2e-spec.ts: take the database from resolveE2eDatabaseUrl() instead of falling back to localhost:5432 before dropping the schema. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): escape host names fully in the egress spec patterns CodeQL flagged js/incomplete-sanitization: only dots were escaped before building a RegExp from the host constants. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…rovider (#39) (#72) * refactor(frontend): remove the SaaS layer from the dashboard Thinker is self-hosted only, so the inherited Manifest Cloud UI goes. The frontend leaves first so no screen breaks when #14/#15 drop the matching backend endpoints. - Billing/plans: delete PlanPicker, UpgradeSuccessModal, UsageLimitBanner, the /upgrade page, the Register ?step=plan picker, the plan stores, the plan-based range locks on the analytics pages, the plan-limit upgrade CTAs in the request views, the Account billing and usage-email sections, and the @better-auth/stripe client plugin and dependency. - API Bot: delete the banner, the sidebar card, the dithered ground, their stylesheet and the SVG asset. - GitHub stars: drop the header star button and its /api/v1/github call. - Free Models: delete the page, its route, its API client and the assets only it used. - Managed Gemini Free: drop the provider entry, icon alias, background /ensure provisioning call and the Calendly key URL. - Cloud branches: checkIsSelfHosted() is gone and every screen behaves as self-hosted (Local providers always listed, local logs copy, CLI login pinned to this host, discovery after signup and setup). Drop the Manifest Cloud origin mapping, the cloud email card, the VITE_MANIFEST_SELFHOSTED read and the Dockerfile ENV that set it. - Help: drop the Manifest Calendly booking link. - Remove the dead CSS for all of the above, update the tests and the inherited dev guide. Closes #12 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(backend): remove billing, Stripe and plan limits Billing, Stripe and the Free/Pro plans belong to the SaaS layer that Thinker drops (docs/decisoes-iniciais.md section 3). - Delete packages/backend/src/billing (PlanService, billing controller, billing emails, request quota window, subscription status) and drop BillingModule from the app, proxy and analytics modules. - Proxy: remove the per-request plan gate (assertWithinRequestLimit) and the PLAN_LIMIT_REQUESTS / M204 handling in the controller and the exception filter. The proxy no longer answers 402 on its own; a 402 follows the generic error path. - Auth: remove the @better-auth/stripe plugin; drop the stripe and @better-auth/stripe dependencies from the backend. - Recording retention: keep only the global path (365-day default or REQUEST_RECORDING_RETENTION_DAYS); per-plan retention is gone. - Tenant entity: drop limit_overrides and billing_email_preferences; delete the TenantRequestUsage entity. - Shared: delete plan-limits and its exports. - Remove the STRIPE_* / PLAN_LIMIT_* / PLAN_REQUEST_QUOTA_RESET_AT variables from .env.example. - New migration DropBillingSchema1803200000000 drops the quota trigger and function, requests.quota_counted, tenant_request_usage, billing_email_logs and the two tenant columns. The old AddTenantRequestUsage migration keeps only its self-hosted path (a no-op up) so it no longer imports deleted billing code. /api/v1/billing/* no longer exists, and the STRIPE_* and PLAN_LIMIT_* variables are ignored if set. Closes #14 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(frontend): remove phone-home and Autofix from the dashboard Thinker makes no outbound calls of its own, and Autofix depended on Manifest's hosted Phoenix service. The dashboard drops both before the backend modules go in #16 and #17. - Update check: VersionIndicator now only shows the build-time __MANIFEST_VERSION__ badge. It makes no request, shows no "new version" link to the manifest.build changelog and has no dismiss state. services/api/version.ts and its test are gone. - Discovery: delete the post-signup questionnaire (page, service, styles, route, tests) and the pending-discovery redirects in AuthGuard and GuestGuard. First-admin setup now lands on / (Overview), signup on /welcome, and social signup also goes to /welcome. A leftover manifest_discovery_pending_* key from an older build no longer redirects anyone. - Wingman: delete the dev drawer, wingman-dev-proxy.ts, the VITE_WINGMAN_* / __WINGMAN_URL__ / __DEV_MODE__ build constants, the App and Welcome mounts, the drawer CSS and the CONTRIBUTING section. - Autofix: delete AutofixKpiCards, SettingsAutofixSection, NotificationBell (it only nagged about inactive Autofix), the Autofix switch and Manifest Terms/Privacy line on harness creation (modal and Welcome), the autofix badges, trigger filter, Phoenix panels, sibling links and status labels in the Requests views, the "Autofixed attempts" connection card, the Doctor tooltip variant, the healed chart series, the autofix fields in services/api/*, the two public PNGs, and the dead CSS. - The generic reliability metrics that the backend still serves under the legacy /overview/autofix-* paths (success rate, fallback recoveries, request status over time, per harness/provider/model reliability) stay. They are now read through neutral clients (getReliabilityStats, getRequestStatusTimeseries, RELIABILITY_PATHS) and shown by ReliabilityKpiCards. "Self-healed" becomes "Recovered" and counts fallback recoveries only. - Update the tests, the design-system registry and the inherited dev guide. Closes #13 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(frontend): opt new harnesses out of legacy Autofix until #16 Review follow-up for #57. - A harness stored without autofix_enabled inherits the backend default. The backend turns Autofix ON when it detects no container (bare-metal npm start, dev runs), and the dashboard no longer has a switch to turn it off. Until #16 removes Autofix from the backend: - createAgent always sends autofix_enabled: false, which covers the Connect Harness modal, Welcome and ConnectProvider; - duplicateAgent follows the copy with PATCH /routing/:agent/autofix {enabled:false}, because the duplicate endpoint has no field for it. Both live in one commented block in services/api/agents.ts, with tests on the request payloads. - The request-status timeseries client folds a legacy `healed` key into `success`. The backend's success rate already counts those requests as successes, so the bars still sum to the request total, Success + Recovered + Error matches the Success rate card, and Recovered stays fallback-only, like its KPI. - The Requests page rewrites a stale ?trigger= value (for example ?trigger=autofix) on load to the filter it actually applies. - Add AuthGuard tests for /cli/auth, with and without a session. - Correct the dev guide: the self-hosted default is OFF only in a container or with MANIFEST_MODE=selfhosted. Document AUTOFIX_GLOBAL_ENABLED=false as the operator workaround for existing harnesses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(backend): remove waitlist, CRM, Gemini Free, free models, GitHub stars and error pages Remove the Manifest Cloud and marketing surfaces from the backend: - waitlist/ (pivot and Autofix claims) and its open-CORS pivot route (applyPivotClaimCors, PIVOT_CLAIM_PATH, PIVOT_CLAIM_CLOUD_ORIGIN). - crm-metrics/ and CRM_METRICS_SECRET. - The managed Gemini Free provider: routing/managed-free-provider/, common/constants/managed-free-providers.ts, the CREDITS_* variables, and its entries in provider-endpoints, provider-client, provider.service, provider-model-fetcher and routing.module. No other provider's endpoint, prefix handling, fallback order or tier resolution changes. - free-models/ (sync from mnfst/awesome-free-llm-apis), github/ (stars from api.github.com) and error-pages/ (public and Peacock push routes, seeders, discovery), MANIFEST_PUBLIC_STATS and ERROR_PAGE_PUSH_SECRET. - gemini-free and the managedFree flag from manifest-shared, and the regenerated CLI provider catalog. - The plan_request_limit_exceeded error class left over from #14. DropSaasFeatureSchema1803300000000 sets a transaction-local lock_timeout, drops waitlist_claims, public_error_pages and the cloud-only IDX_requests_autofix_healed index, and deletes every gemini-free connection with its agent grants. Request history keeps its provider label, and routes that still name gemini-free resolve as unavailable and fall through to their fallbacks, as after a disconnect. down() restores the two tables as the self-hosted path created them. Closes #15 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(backend)!: remove Autofix and the Phoenix healer from the backend Autofix sent failing requests to Manifest's hosted healer (autofix.manifest.build) and pinged it at every production boot. Thinker makes no such call (#16). The local self-heal of v0.6 will build on the fallback chain on its own terms. - Delete routing/autofix (AutofixService, healing clients, health probe, observation reporter, Phoenix types and vendored contract) and the contract:refresh script with its ajv/js-yaml devDependencies. - Proxy: drop the heal-once branch from the primary and fallback hops and the wire-body retry hook from ForwardResult. A failed request now goes straight to shouldTriggerFallback, exactly as for an agent that never opted in. The primary is always attempt 1, the x-manifest-provider / x-manifest-auth-type replay rewrite is gone, and the recorder writes no repair columns or auto_fixed rows. - Analytics: move the generic reliability metrics to /api/v1/overview/reliability/{stats,timeseries,per-agent,per-provider, per-model} without the Autofix fields; drop the healed disposition, the auto_fixed counter, the autofix trigger filter and the connection breakdown's Autofix attempts. - Remove /autofix/status, /autofix/enable-all, the per-harness /routing/:agent/autofix endpoints, the autofix_enabled create field, the MCP Autofix tools and the CLI `routing autofix` command and `--autofix`. - Schema: DropAutofixSchema1803400000000 drops the autofix columns, check constraint and indexes (lock_timeout, IF EXISTS, full revert). 1802200000000 now runs its self-hosted no-op path everywhere. - Shared: drop deriveAutofixStatus, AUTOFIX_STATUSES and auto_fixed. - Delete the unused doctor-release email. - Frontend: call the neutral reliability paths and drop the temporary autofix_enabled opt-out, the duplicate PATCH and the healed fold. - Docs: move the PoC spec to docs/referencia/, remove AUTOFIX_* from the guide, .env.example and the Docker README. BREAKING CHANGE: the Autofix API, analytics paths, MCP tools and CLI command are removed; the reliability analytics moved to /api/v1/overview/reliability/*. Closes #16 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(backend)!: remove phone-home from the backend and the CLI Thinker makes no outbound call of its own. Remove every upstream phone-home from the backend and the CLI: - usage telemetry (telemetry/, InstallIdService, PayloadBuilderService, the InstallMetadata entity) and the CLI usage spool (packages/cli/src/telemetry.ts); - the daily update check (version/, GET /api/v1/version, the GitHub releases URL); - the discovery forwarding to blue.manifest.build (discovery/, POST /api/v1/discovery/complete); - Sentry (instrument.ts, sentry/, SentryModule/SentryGlobalFilter, the @sentry/nestjs dependency); - the hosted Wingman origin in CORS and CSP frame-src; frame-src is 'self' in every mode and WINGMAN_CORS_ORIGINS becomes THINKER_CORS_ORIGINS with the same meaning; - the modelparams.dev fetch on boot and hourly cron; parameter specs come only from the bundled modelparams package snapshot. DropInstallMetadata1803500000000 drops the install_metadata table (lock_timeout, IF EXISTS, revert recreates it empty). The removed variables leave docker-compose, the .env examples, the Docker README, the deploy templates and the developer guide. A new e2e guard fails if the backend, CLI or shared source names a removed destination again, or if a production-mode boot of the real server fetches or resolves anything outside the ADR 0003 catalogs. BREAKING CHANGE: GET /api/v1/version and POST /api/v1/discovery/complete are gone, the hosted Wingman origin is no longer allowed by CORS, and WINGMAN_CORS_ORIGINS is renamed THINKER_CORS_ORIGINS. Closes #17 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): default to a local gateway instead of Manifest Cloud With no --url, MANIFEST_URL or stored login, the CLI targeted https://app.manifest.build, so a MANIFEST_API_KEY set without a host went to Manifest's cloud. DEFAULT_URL is now http://localhost:2099, the default Thinker port, and the invalid-URL hint and README follow. The backend's 404 hint for /chat/completions told callers to point their baseURL at https://app.manifest.build/v1; it now refers to this gateway. The egress guard now fails on app.manifest.build or gateway.manifest.build anywhere in the CLI or shared source (tests included), on a new backend production file naming them, on a CLI default that is not local, and on a boot request to either host. The three remaining backend files (Cloud trusted origins, the dashboard link fallback and the OG-tag placeholder) are pinned for #18, #22 and #25 and may only shrink. Refs #17 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(backend): single self-hosted mode, drop MANIFEST_MODE Thinker has one deployment mode. The backend no longer decides between "cloud" and "self-hosted" from MANIFEST_MODE or container markers (/.dockerenv, /run/.containerenv, KUBERNETES_SERVICE_HOST); it always keeps the former self-hosted behavior, on any runtime: - built-in local providers (Ollama, LM Studio, llama.cpp) are always available: the cloud-only filters, the M303 rejection and its error code are gone; - custom-provider URLs validate with allowPrivate: LAN, loopback and http:// destinations are a feature, http:// to a public host is still refused, and cloud metadata endpoints stay blocked (now also by name: metadata.google.internal, metadata.goog, metadata, instance-data); - request recordings fall back to the filesystem without S3 credentials; - the boot backfills always run on the app's DATABASE_URL connection; - GET /api/v1/setup/status drops isSelfHosted and always probes Ollama. The CIMD client_id fetch does NOT inherit the old self-hosted allowance: that URL comes from an unauthenticated MCP client, so it is public-only by default (DNS failure is an error), with THINKER_CIMD_ALLOW_PRIVATE=true as the opt-in for LAN-hosted clients. auth.instance.ts no longer trusts the Manifest Cloud hosts (app/gateway.manifest.build) as origins or MCP resources; MCP is bound to the canonical BETTER_AUTH_URL origin only, and the file leaves the no-phonehome allow-list. detect-self-hosted.ts becomes container-host.ts with only getContainerHostAlias(). Unit tests no longer depend on /.dockerenv. Closes #18 Closes #46 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(backend): add THINKER_CATALOG_SYNC and gate the OpenCode Go doc on a provider Implements ADR 0003 (#39): - THINKER_CATALOG_SYNC=false (also 0/no/off) turns off all three public catalog fetches: no boot fetch, the daily crons and the pricing/model refresh paths become no-ops, and the OpenCode Go catalog returns [] without fetching. OpenRouter and models.dev stay on by default. - OpencodeGoCatalogService only warms the raw.githubusercontent.com doc at boot when a tenant_providers row for OpenCode Go (id or alias) exists. Every other caller is already scoped to an OpenCode Go provider, so a newly registered provider loads the doc lazily through its discovery. - pricing-health and pricing/refresh report sync_enabled, and the routing status (REST and MCP) no longer blames the OpenRouter cache, which is empty by design with the sync off. - The egress e2e boots the real server three times: no OpenCode Go provider (OpenRouter and models.dev fetched, no raw.githubusercontent.com), provider + THINKER_CATALOG_SYNC=false (no remote fetch at all), and provider + default (the doc is warmed). - Documents the variable in both .env.example files, the compose file, DOCKER_README and the dev guide, including what pricing loses when the sync is off. Closes #39 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(backend): pin custom-provider connections against DNS rebinding Review of #71 (S1): with allowPrivate now constant for custom providers, a DNS failure passed validatePublicUrl, and fetch then resolved the name again with no check. A hostile resolver could answer a public address (or fail) during validation and 169.254.169.254 at connect time, so the probe and the forward could reach cloud metadata. - New common/utils/ssrf-safe-fetch.ts: undici fetch with a shared Agent whose connect.lookup resolves once, refuses the connection when any answer is a metadata address, and hands the socket only validated addresses. Metadata literals and names are refused before any socket. A DNS failure fails the request. - The custom-provider probe and the provider-client forward for user-supplied endpoints (requiresSsrfRevalidation) use it. - validatePublicUrl treats a DNS failure as an error even with allowPrivate (a .invalid host is refused). - S2: block the AWS container credential endpoints 169.254.170.2 (ECS), 169.254.170.23 and fd00:ec2::23 (EKS Pod Identity). - N2: classify IMDS embedded in IPv6 (IPv4-compatible, NAT64 64:ff9b::/96, 6to4, Teredo) as metadata; IPv6 metadata matches any textual form. - undici 6.29.0 becomes a backend dependency (the root override already pins undici ^6); Node's built-in fetch cannot take a foreign Agent across Node versions, so undici's own fetch is used. Tests: unit specs for the lookup and the classifier, and an e2e where a hostname resolves to a public address at validation and to 169.254.169.254 at connect: the probe and the forward are refused and a listener standing in for the metadata address receives 0 connections (it receives them when pinning is removed). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the billing drop e2e through the database guard Refs #67 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the SaaS drop e2e through the database guard Refs #67 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the Autofix drop e2e through the database guard The DropAutofixSchema e2e spec opens its own DataSource with dropSchema, so it now takes its URL from resolveE2eDatabaseUrl() like the other migration specs instead of falling back to a default localhost database. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): route the install-metadata drop e2e through the database guard The DropInstallMetadata migration spec and the no-phone-home egress spec both open a dropSchema connection. Resolve their URL with resolveE2eDatabaseUrl() from test/e2e-db-guard instead of falling back to localhost:5432, so neither can wipe a database that is not an explicit, disposable test database (#67, #69). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): drop MANIFEST_MODE from local-runner specs and fix the local log flake - Remove the MANIFEST_MODE=selfhosted setup that #100, #103 and #104 added to provider-client.local-servers.spec.ts, local-providers.e2e-spec.ts, reserved-local-runner-aliases.e2e-spec.ts and playground-request-headers.e2e-spec.ts. There is one mode now, so the variable does nothing. - local-providers.e2e-spec.ts: "logs local requests under the canonical provider at zero cost" read rows[0] of every llama.cpp row for the agent, with no ORDER BY, while earlier tests also log llama.cpp requests and a row starts as `pending` before its usage lands. Tag the request with its own traceparent and wait for that one settled row. Closes that part of #101. - mcp-cimd-ssrf.e2e-spec.ts: take the database from resolveE2eDatabaseUrl() instead of falling back to localhost:5432 before dropping the schema. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): escape host names fully in the egress spec patterns CodeQL flagged js/incomplete-sanitization: only dots were escaped before building a RegExp from the host constants. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Closes #13
What changes
The dashboard stops making outbound or Manifest-hosted calls of its own and drops the Autofix UI. This PR is frontend only. The backend modules go in #16 (Autofix) and #17 (telemetry, version, discovery, Sentry, Wingman/CORS).
VersionIndicatoronly rendersv{__MANIFEST_VERSION__}.vite.config.tsinjects that constant at build time from the canonicalpackages/manifest/package.json. The component makes no request, has no "new version" link to the manifest.build changelog and keeps no dismiss state.services/api/version.tsis deleted.services/discovery.ts,discovery.css, the/discoveryroute and its tests. The pending-discovery redirects inAuthGuardandGuestGuardare gone, andAuthGuardno longer needs itsrouteCheckedsignal./, which redirects to/overview. If auto sign-in fails, it goes to/login./welcome, the step that used to follow Discovery.manifest_discovery_pending_*key from an older build no longer redirects anyone. Tests cover this.WingmanDevTools,wingman-dev-proxy.tsand its Vite plugin,VITE_WINGMAN_*,__WINGMAN_URL__and__DEV_MODE__. Also gone: the mounts inAppandWelcome, the drawer CSS and the Wingman section of CONTRIBUTING.AutofixKpiCards,SettingsAutofixSectionandNotificationBell, whose only notification was "Autofix is inactive". Also removed:AddAgentModalandWelcome);Autofix: …status and theAutofixedlabel;healedchart series;services/api/*;public/autofix-icon-email.png,public/banner-autofix-gradient.pngand the dead CSS./overview/autofix-*paths: success rate, fallback recoveries, request status over time, and per-harness/provider/model reliability.getReliabilityStats,getRequestStatusTimeseries,getPer*Reliability), and the paths live in oneRELIABILITY_PATHSconstant.ReliabilityKpiCardsshows four cards: Success rate, Recovered requests, Recovered by Fallback, Failed requests.autofix_enabledinherits the backend default. That default is ON whenever the backend detects no container (bare-metalnpm start, dev runs), and the dashboard no longer has a switch to turn it off. So, in one commented block inservices/api/agents.ts:createAgentalways sendsautofix_enabled: false. This covers the Connect Harness modal, Welcome and ConnectProvider.duplicateAgentfollows the copy withPATCH /routing/:agent/autofix {enabled:false}, because the duplicate endpoint takes no such field.AUTOFIX_GLOBAL_ENABLED=falseas the operator workaround (orMANIFEST_MODE=selfhosted).healedseries: a pre-Remover Autofix/Phoenix do backend #16 backend can still return ahealedkey in the request-status timeseries. The client folds it intosuccess, because the backend's success rate already counts those requests as successes. That way:?trigger=: on load, the Requests page rewrites an unknown or legacy?trigger=value (for example?trigger=autofix) to the filter it actually applies.Acceptance grep
grep -rniE "autofix|healed|wingman|/discovery|version-check|updateAvailable" packages/frontend/srcmatches only three documented, temporary legacy blocks, all removed by #16:services/api/analytics.ts: theRELIABILITY_PATHSblock (five backend paths) and thehealedfold;services/api/agents.ts: the Autofix opt-out.These are generic reliability endpoints the dashboard still needs. The backend exposes them only under these names, and backend changes are out of scope here. When #16 deletes
autofix-stats.service.ts, it must:Otherwise the Overview KPIs, the request-status chart and the reliability columns break.
Gates (local, until #20)
npm run lint(frontend)no-unused-vars/no-explicit-any)tsc --noEmit -p packages/frontend/tsconfig.jsonvite buildvitest run(local TZ, UTC-3)TZ=UTC vitest runnode scripts/check-design-tokens.mjsnpm run design:registry:checkandnode --test scripts/design-registry.test.jsIn the built bundle:
grep -E "wingman|blue\.manifest|/api/v1/version|telemetry\.manifest"finds nothing.autofixappears only in the fiveoverview/autofix-*paths.How to verify
/setupand create the admin. It should land on/overviewwith no/discoverystep./register(when signup is enabled) and create an account. It should land on/welcomewith no/discoverystep./messages), the attempts filter offers only With a fallback attempt and No recovery attempt. An old?trigger=autofix,fallbacklink filters by fallback and rewrites the URL to?trigger=fallback. A?trigger=autofixlink is cleared.POST /api/v1/agentsbody carriesautofix_enabled: false. A duplicate is followed byPATCH …/routing/<copy>/autofix.Still pending
qa-docker: the issue's HAR/Playwright run over Login, Setup, Overview, Messages, Settings and harness creation, checking that the browser calls no host other than the instance. This must pass before the PR leaves draft.🤖 Generated with Claude Code