Saltar al contenido principal
El contenido detallado del log está originalmente en inglés (es un changelog técnico). Cuando un cambio afecta la UI o la experiencia del usuario, los títulos y descripciones se traducen aquí.

Novedades — semana del 25 de mayo de 2026

Resumen de lo que se publicó esta semana, en lenguaje de usuario. El log técnico completo está más abajo.

Nuevo

  • Notas del autor en documentos. Ahora puedes adjuntar notas cortas a un documento antes de extraer para guiar cómo kb2b lo interpreta — por ejemplo, “material de marketing del proveedor X” o “borrador, no aprobado”. Las notas no se convierten en facts y no aparecen en el chat: solo enmarcan la lectura del documento. Hasta 5 notas por documento, 16 KB en línea o 80 KB como archivo. Ver Notas del autor.
  • Sugerencias automáticas de notas. Al subir un documento, kb2b lo lee con un modelo rápido y propone borradores de notas si detecta señales útiles (un JSON con $schema externo, tono claramente promocional, etc.). Aceptas la sugerencia con un clic, la editas, o la ignoras y escribes la tuya.
  • Chips de contexto bajo cada fact. Los facts extraídos de un documento con notas ahora muestran chips ámbar con el nombre de cada nota que estaba activa durante la extracción. Es la pista visual de bajo qué encuadre se leyó el documento, un nivel por encima de la provenance habitual. Ver Contexto de un fact.
  • Rastro cuando una nota se borra. Si alguien borra una nota después de que ya se hayan extraído facts con ella, los facts no pierden la pista: el chip pasa a gris con texto “Adjunto eliminado”, para que el equipo sepa que en su día hubo guía especial.

Novedades — semana del 18 de mayo de 2026

Resumen de lo que se publicó recientemente, en lenguaje de usuario. El log técnico completo está más abajo.

Nuevo

  • Panel de Conocimiento (Trust Dashboard). La sección Memoria pasa a llamarse Conocimiento y abre en un panel que responde de un vistazo a “¿puedo fiarme de lo que hay en esta base de conocimiento?” — contradicciones pendientes, cobertura de validación, frescura, cola de “necesita revisión” y evidencia reciente, todo en una sola página. Ver Conocimiento y confianza.
  • Top-ups de horas de reunión. ¿Te quedas sin minutos a mitad de ciclo? Ahora puedes comprar packs sueltos de horas (5h, 15h, 30h o 100h) sin cambiar de plan. Los minutos comprados no caducan — quedan en tu cuenta hasta que los uses. Ver Planes y precios.
  • Salida en la misma página cuando llegas a un límite. Pulsar Importar al tope de minutos abre un selector de top-up en lugar de un error sin salida, y en ajustes de reuniones aparece un panel “comprar horas extra” al cruzar el 80% de uso.
  • Top-ups para planes de cortesía. Los workspaces con plan otorgado por administrador ya pueden comprar packs de tokens y de horas, anclados a la duración de su cortesía.

Cambios

  • Las contradicciones aparecen en toda la sección Conocimiento. El banner de triaje (lista, severidad, posturas, resolver, discusión) ya no está escondido dentro de la pestaña Constitución: se muestra en todas las sub-pestañas de Conocimiento. Los enlaces directos desde notificaciones y dashboard abren el banner al instante. Ver Contradicciones y resolución.
  • Página de suscripción totalmente traducida. Cada texto de /dashboard/settings/subscription respeta ahora el idioma elegido (ES / EN / CA), incluidas fechas, badges de estado, tarjetas de top-up y el flujo de eliminar cuenta.
  • Tarjetas de plan más honestas. Las tarjetas ya no muestran “X documentos” como si fuera un límite duro: documentos y consultas por día se muestran como estimaciones (≈) con nota al pie. Los tokens siguen siendo el único tope real. Ver Planes y precios.
  • Página de detalle por documento. Cada documento tiene ahora su propia página con histórico de extracciones, hechos paginados, descripción editable y enlaces cruzados a las contradicciones donde aparece o a las síntesis de campaña que lo originaron.
  • Texto más claro al eliminar workspace. La zona de peligro de tu perfil ahora dice “Eliminar este workspace” en lugar de “Eliminar cuenta y organización”, porque es lo que realmente hace.

Correcciones

  • Crítico: eliminar un workspace ya no borra tu cuenta. Antes, pulsar Eliminar en la zona de peligro podía sacarte silenciosamente de todos los demás workspaces a los que pertenecías. Ahora solo se elimina el workspace activo; tu cuenta y el resto de pertenencias quedan intactas.
  • El quick-start “Captura reuniones” del onboarding vuelve a funcionar. Empezar desde la plantilla de reuniones ya no falla con un error de “No se pudo crear la base de conocimiento”.
  • Mejores mensajes cuando un top-up no está configurado. Si un producto de top-up no está dado de alta en el entorno, el botón de compra ahora muestra un mensaje claro en lugar de un fallo genérico de red.
  • El email de cuota superada lleva directamente a la pestaña de horas y usa el texto correcto “Comprar horas extra”.

kb2b (web)

[Unreleased]

[0.15.1] - 2026-05-17

Fixed

  • CRITICAL — workspace deletion no longer wipes your account. The Danger zone in /dashboard/profile previously called an endpoint that, after deleting the active workspace, also deleted the user row. Because organization_member.userId cascades on user delete, that silently unlinked the user from every OTHER workspace they belonged to, leaving them dropped onto the onboarding screen with no visible workspaces. The endpoint now deletes only the active workspace; the account and all other workspaces stay intact. Copy in ES/EN/CA has been rewritten to say “Eliminar este workspace” / “Delete this workspace” (no longer “Eliminar cuenta y organización” / “Delete account and organization”) so the intent matches what actually happens. A regression test in src/__tests__/api-account-delete.test.ts asserts that a user with memberships in two workspaces keeps the second after deleting the first.

[0.15.0] - 2026-05-17

Changed

  • Contradictions move from the Constitution tab to the Knowledge section. The full triage banner (list, severity, stances, resolve, discussion) now lives in the Knowledge layout, so it appears on Dashboard, Updates, and Constitution alike. Clicking Pending contradictions on the dashboard no longer bounces you to the Constitution tab with a collapsed panel that needs a second click — the banner is right there, ready to expand. Deep-links (?contradiction=<id>) work from any sub-tab. The banner still self-hides when there are no contradictions, so tabs with a clean knowledge base render exactly as before.

Removed

  • Dashboard’s compact Pending contradictions summary card — the layout-level banner shows the same count + severity in its collapsed header.
  • The /dashboard/knowledge?contradiction=<id>/constitution redirect (no longer needed; banner is everywhere).

[0.14.1] - 2026-05-17

Fixed

  • Onboarding “Capture meetings” quick-start no longer fails with “Could not create the knowledge base. Please try again.” The SciPot client was calling the old POST /pots/from-json endpoint, which was renamed to POST /pots on the SciPot side and now returns 405. Updated the client to use the new canonical create route. Request body, headers, and response shape are unchanged.

[0.14.0] - 2026-05-17

The Memory section becomes Conocimiento (English path /dashboard/knowledge, localized label in es / en / ca) and is restructured into a Trust Dashboard with sub-routes. The orphan /dashboard/activity page gets folded into a proper sub-route. Per-document detail moves to a canonical /dashboard/documents/[id] route with provenance cross-links to contradictions and campaign syntheses. The Trust Dashboard answers “can I trust what’s in this knowledge base?” at a glance, with five signals:
  • Contradictions — first-class summary card with severity badges (critical / moderate / mild); deep-link goes straight to the full triage UI on the constitution sub-route.
  • Engagement summary — compact strip showing 7d actions, active users, week-over-week delta and a tiny sparkline. “Ver detalle” jumps to the full engagement widget on the activity sub-route.
  • Validation coverage — % of facts with ≥1 validation, with healthy / at-risk progress bar (≥70% threshold).
  • Freshness — % of facts touched in the last 30 days, paired with coverage in a 2-column grid so the “ever validated” + “still current” question is one glance.
  • Needs review queue — top-10 unvalidated facts sorted by lowest POT score (most-uncertain first). Empty state celebrates “all caught up” instead of leaving an awkward blank.
Old URLs keep working via 308 redirects (/dashboard/pot/dashboard/knowledge, /dashboard/activity/dashboard/knowledge/activity), so bookmarks and external links don’t break.

Added

  • Trust Dashboard at /dashboard/knowledge composing ContradictionsSummaryCard, EngagementSummaryStrip, ValidationCoverageCard, FreshnessCard, NeedsReviewQueue, and RecentFacts (limit=4).
  • New sub-routes: /dashboard/knowledge/activity (full engagement widget + recent facts + activity feed) and /dashboard/knowledge/constitution (axioms + active campaigns + danger zone + full ContradictionsBanner triage).
  • New /dashboard/documents/[id] route as the canonical per-doc viewer (extraction history + paginated facts + metadata editor + mounted FactInspectorModal for ?fact= deep-links).
  • Per-document cross-link sections:
    • Contradicciones que involucran este documento — edges where any fact endpoint comes from the doc.
    • Síntesis de campaña — campaigns whose latest synthesis was uploaded as this document.
  • Three new API endpoints:
    • GET /api/documents/[id]/contradictions — in-memory join of doc-facts × contradicts edges in the active POT.
    • GET /api/documents/[id]/campaigns — campaign syntheses sourcing this document (via campaign_synthesis.scipotDocumentId).
    • GET /api/pot/facts/needs-review?limit=10 — facts never validated, ordered by POT score asc.
    • GET /api/metrics/freshness?window_days=30 — fraction of facts updated within the window.
  • Shared sub-nav layout component for /dashboard/knowledge/* with Panel / Novedades / Constitución links (localized per profile language).
  • requireWorkspaceAndPot() shared server auth helper now used by every /dashboard surface that needs an authenticated session + active POT.
  • 29 new knowledge.* i18n keys with full parity across es / en / ca (87 entries total).
  • 11 new test files (101 cases) covering the new endpoints, redirect contract, i18n key presence in all three locales, and PATCH allowlist behavior.

Changed

  • Sidebar nav renamed Memoria → Conocimiento. URL path /dashboard/pot/dashboard/knowledge; existing path 308-redirects to the new one.
  • PATCH /api/documents/[id] now hard-allowlists source_url and description; any other body field is silently dropped and an empty payload returns 400. Closes a write-amplification surface the UI was never using but the route accepted blindly.
  • Sidebar Documents row click now navigates to /dashboard/documents/[id] (canonical detail route). Old ?doc=<id> deep-links from recent-documents.tsx and other callers point at the new URL directly.
  • DocumentDetailView extracted from pot-documents.tsx into src/components/documents/document-detail-view.tsx so it can be shared by the dedicated route. Copy-link button now emits the new /dashboard/documents/[id] URL.
  • RecentFacts accepts a limit prop (defaults to 8; Trust Dashboard uses 4 for “Recent evidence”).
  • Contradiction navigation across the app (FactInspectorModal, ContradictionsBanner copy-link, NotificationBell edge clicks) now lands on /dashboard/knowledge/constitution?contradiction=<id> directly, skipping the redirect hop.
  • Fact deep-links (scout-fact-sheet, FactInspectorModal copy-link, NotificationBell fact clicks, contribution-confirmation, onboarding redirect, dashboard root redirect, campaigns/[token]/workspace redirect, demo page links) point at /dashboard/knowledge directly.

Removed

  • src/app/dashboard/pot/page.tsx (orphaned by the /dashboard/knowledge rewrite; sub-routes /pot/agents, /pot/campaigns, /pot/meetings remain — they’re separate features).
  • src/app/dashboard/activity/page.tsx (replaced by the new /dashboard/knowledge/activity sub-route; the old URL 308-redirects).
  • src/components/pot/pot-dashboard.tsx, src/components/pot/pot-documents.tsx, and src/components/pot/pot-overview.tsx (no remaining importers after the Trust Dashboard rewrite).
  • Deprecated i18n keys (21 entries across es / en / ca): nav.memory, nav.activity, pot.overview, pot.documents, activity.title, activity.description, activity.timeline.

Security

  • PATCH /api/documents/[id] allowlists writable fields (see Changed), preventing accidental mutation of internal fields like uploaded_by_contributor_id or pot_score via crafted requests.

[0.13.0] - 2026-05-16

The whole /dashboard/settings/subscription surface is now i18n’d — every visible string routes through the existing useLanguage().t() dictionary with es / en / ca variants. Workspaces switching languages finally see the subscription page respect the chosen locale instead of staying frozen on Spanish. Also drops the misleading “X documentos” line from the plan cards. Documents was never enforced as a hard cap on the KB2B side (syncQuotasToSciPot only ever passes max_monthly_tokens), so the number was display-only and gave customers the wrong mental model. Now docs and queries-per-day render as derived estimates with a prefix ”≈” and a footnote (“estimado, depende del uso”). Tokens stays as the only real ceiling.

Added

  • ~85 new translation keys spanning subscription.*, topup.*, deleteAccount.*, and consumption.* namespaces, with full parity across es / en / ca.
  • <SubscriptionPageHeader> client wrapper so the (async) page Server Component can delegate header rendering to a child that consumes useLanguage().

Changed

  • <PlanSelector> cards now render docs/queries as estimates with the ”≈” prefix and a shared ”* estimated, depends on usage” footnote below the grid. Tokens / meeting-hours / members stay as hard caps above the fold.
  • <SubscriptionBilling> — status badges, cancellation banner, admin-granted banner, and plan-selector title all go through the dictionary. Date formatting honors the active locale instead of hardcoding "es-ES".
  • <TopupSection> and helpers (SuccessBanner, CanceledBanner, ErrorBanner, HoursTab, HoursTabIneligible, TopupPackCard) now consume translations. The three HoursTabIneligible reasons share a single render path off translation-key tuples.
  • <DeleteAccountSection> — both the entry-point danger panel and the confirmation panel are translated. Org name interpolation keeps the visible <strong> styling on the org name through a small __ORG__ placeholder split.
  • <SubscriptionConsumption> + <ConsumptionMini> — the wrapper title, “view detail” toggle, and the three near-limit / over / blocked tail messages are translated. The collapse content (<ConsumptionView>) is still hardcoded Spanish — flagged as a follow-up in the wrapper.

Notes

  • The “X documentos” → ”≈ X documentos/mes*” reframe is UI-only. KB2B never enforced documents as a quota — syncQuotasToSciPot always only passed max_monthly_tokens to SciPot, and SciPot’s own max_documents_per_pot: 50 default is applied uniformly to every workspace regardless of plan. No backend change is needed to align the UI with reality.
  • Token top-up pricing is unchanged. Reviewed the margins (3.6x → 2.6x cost) and the principle “top-up rate > plan rate” from the v0.10.0 spec stays — keeps the upgrade signal intact.

[0.12.0] - 2026-05-16

Meeting-hours top-up bonuses no longer expire. Customers who buy a pack keep those minutes until they use them — same semantics as token top-ups, which have always persisted indefinitely. The cycle-end cliff (introduced in v0.11.0) caused two problems in PROD: customers buying late in their cycle got short-changed (or refused outright by the 1-hour-runway gate), and the Stripe product description claimed an expiry that mismatched the actual UX customers expected.

Changed

  • Hours bonus minutes persist indefinitely. getCapMinutes no longer checks bonusMeetingMinutesExpiresAt; bonus always counts. The column stays on the schema (NOT NULL on meeting_hours_topup, nullable on subscription) for historical rows, but is no longer load-bearing.
  • Eligibility check simplified. Dropped the period_end_too_soon reason from canBuyHoursTopup (no anchor to protect anymore). The helper now rejects only on no_sub, cancelling, and override_active. The 1h Stripe-session-expiry cap is gone; sessions use Stripe’s default 24h.
  • Webhook credit simplified. The CASE-WHEN expression that reset the running bonus balance when the previous expiry had passed is gone — straight bonusMeetingMinutes + minutesPurchased SQL increment (still race-safe under concurrent webhooks).
  • Stripe product description fixed. The hours top-up product no longer reads “Expires at the end of the current billing cycle” — it matches the actual behavior.
  • UI copy updated across <TopupSection>, <MeetingQuotaExceededModal>, the meetings-settings inline panel, and the quota-exceeded email. All four surfaces now describe top-ups as “persist hasta que las uses” instead of “caducan al final del ciclo”.
  • /api/meetings/quota-status response shape drops bonusExpiresAt (no longer meaningful).

Note for operators

If you previously had customers refused by period_end_too_soon near their cycle end, that gate is gone. Existing rows in meeting_hours_topup and subscription with historical expiry timestamps are preserved but no longer affect the read path — customers with “expired” bonus minutes on their account effectively just got those minutes credited.

[0.11.2] - 2026-05-16

Hotfix on the v0.11.x top-up flow surfaced during local dogfooding: when the STRIPE_PRICE_TOPUP_* (or STRIPE_PRICE_HOURS_TOPUP_*) env var was unset, the buy click crashed with SyntaxError: Unexpected end of JSON input in the browser and a misleading “couldn’t reach server” banner — hiding the real (operator-fixable) cause.

Fixed

  • Token and hours checkout routes now wrap the price-id lookup in try/catch and respond with a clean 503 + JSON body ("Token top-up is not configured on this environment yet. Contact support."). Previously a missing env var threw an unstructured 500 with no body, which the client’s res.json() tried to parse and exploded on.
  • <TopupSection> checkout handler now defensively parses the response as text-first, falls back gracefully when the body isn’t JSON, and surfaces a useful message including the HTTP status when it has no structured error to show — so an operator-side misconfiguration is legible in the UI instead of misattributed to a network failure.

[0.11.1] - 2026-05-16

Bug-fix patch on the v0.11.0 hours top-up flow. Two real PROD problems: admin-granted (“cortesía”) plan users couldn’t buy top-ups at all, and the admin grant endpoint accepted arbitrary durations up to 36 months (effectively unbounded cortesía).

Added

  • Admin-granted plan users can now buy meeting-hours and token top-ups. The buy flow anchors bonusExpiresAt to adminGrantedUntil via a new getEffectivePeriodEnd helper. Same atomic-credit semantics as paid subs; the bonus disappears from the quota read path when the grant cliff passes.
  • getEffectivePeriodEnd(sub) helper in topup-eligibility.ts — returns currentPeriodEnd for Stripe subs and falls back to adminGrantedUntil for cortesía. Single source of truth for “when does this billing window end?” used by checkout, the subscription API, the quota-status endpoint, the meetings page, and the at-quota modal.

Changed

  • <TopupSection> is now visible to admin-granted workspaces in /dashboard/settings/subscription. The isPaid gate widened to accept adminGrantedPlan === true alongside Stripe subs. Pure-trial Spark users remain excluded by design (no Stripe customer, no cycle to anchor to).
  • Ineligibility copy “Your billing period ends too soon” → “Your plan ends too soon” — works for both Stripe billing cycles and admin-grant cliffs without sounding off.

Fixed

  • Admin grant endpoint capped at 3 months. The /api/admin/workspaces/ [id]/grant-plan validation previously allowed 1–36 months; the admin UI dropdown defaulted to 36 as the max. Both are now capped at 3. Long-lived cortesía should be a contract or a recurring Stripe sub, not an admin override that drifts. Also bounds the blast radius of an accidental click in the admin panel.

[0.11.0] - 2026-05-16

Closes the v0.10.x top-up redesign milestone (Option A v1 per the autoplan spec). The landing page promised three top-up products since v0.9.0; v0.10.0 made tokens real, this release makes meeting hours real and scrubs the Members promise that won’t ship for now. Users at quota — or close to it — now have a same-page path forward instead of a dead-end CTA. The Hours top-up flow mirrors the Tokens 3-gate idempotency from v0.9.1, with two intentional structural differences: credit lands locally in the KB2B DB (no SciPot round-trip), and bonus minutes carry an absolute expiry timestamp captured at purchase so a plan upgrade mid-cycle can’t silently extend minutes the customer already paid for.

Added

  • Meeting-hours top-up as a one-shot purchase. Four packs: Bump 5h €15 / Boost 15h €38 / Stretch 30h €60 / Mega 100h €120 (€/h decreases €3 → €1.20, always ≥2× operating cost). Expires at the end of the current billing cycle; non-refundable once credited.
  • Tabbed top-up UI at /dashboard/settings/subscription. Tokens and Horas de meeting live behind separate tabs, deep-linkable via ?tab=tokens|hours. The per-plan recommended pack gets a border-primary highlight and “Recomendado” badge on both tabs.
  • Inline “Buy extra hours” panel in /dashboard/settings/meetings whenever usage crosses 80% of the effective cap (plan + non-expired bonus). Same <HoursTopupPicker> as the main tab, in compact form.
  • At-quota import modal on /dashboard/meetings: clicking Import now pre-checks the meeting cap and, if you’re already at it, opens <MeetingQuotaExceededModal> with the Hours packs instead of the import form. Server-side hard-block at 110% remains the authority.
  • Post-checkout success banner reading ?topup=success&type=&qty= so the user gets immediate visual confirmation that the payment landed.
  • Inline error banner with retry on Stripe failures (replaces the prior window.alert() fall-through).
  • Quota-status read endpoint /api/meetings/quota-status used by the web import-flow pre-check (read-only, no Stripe sync).
  • Shared formatPrice helper in src/lib/billing/format.ts using Intl.NumberFormat("es-ES") so prices render consistently across plan-selector, top-up tabs, and modals.

Changed

  • Quota-exceeded email (sendMeetingQuotaExceeded) CTA now reads “Comprar horas extra” and deep-links to /dashboard/settings/subscription?tab=hours&from=quota-email. Body copy reframed around buying hours for the current cycle, with plan upgrade as the secondary option for repeat buyers.
  • Landing-page pricing copy (en/es/ca, 6 strings) no longer mentions the Members add-on. Tokens and Hours promises stay — both ship in v1.
  • getCapMinutes() in src/lib/meetings/quota.ts now returns the effective cap (plan + non-expired bonus) plus a breakdown of planMinutes / bonusMinutes / bonusExpiresAt. Existing callers pick up the bonus automatically without code changes.

Fixed

  • Subscription cycle rollover correctly drops expired bonus minutes without a background sweeper — the expiry check is part of the read path on every quota query.

kb2b Desktop

  • v0.7.2 (2026-05-14) — release: v0.7.2
  • v0.5.0 (2026-05-12) — release: v0.5.0
  • v0.4.0 (2026-05-10) — release: v0.4.0
  • v0.3.0 (2026-05-06) — release: v0.3.0
  • v0.2.1 (2026-05-05) — release: v0.2.1
  • v0.2.0 (2026-05-03) — release: v0.2.0
  • v0.1.8 (2026-05-02) — release: v0.1.8
  • v0.1.7 (2026-04-28) — release: v0.1.7