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
$schemaexterno, 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/subscriptionrespeta 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/profilepreviously called an endpoint that, after deleting the active workspace, also deleted the user row. Becauseorganization_member.userIdcascades 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 insrc/__tests__/api-account-delete.test.tsasserts 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>→/constitutionredirect (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-jsonendpoint, which was renamed toPOST /potson 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.
/dashboard/pot → /dashboard/knowledge,
/dashboard/activity → /dashboard/knowledge/activity), so bookmarks
and external links don’t break.
Added
- Trust Dashboard at
/dashboard/knowledgecomposingContradictionsSummaryCard,EngagementSummaryStrip,ValidationCoverageCard,FreshnessCard,NeedsReviewQueue, andRecentFacts(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 ×contradictsedges in the active POT.GET /api/documents/[id]/campaigns— campaign syntheses sourcing this document (viacampaign_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-allowlistssource_urlanddescription; 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 fromrecent-documents.tsxand other callers point at the new URL directly. DocumentDetailViewextracted frompot-documents.tsxintosrc/components/documents/document-detail-view.tsxso it can be shared by the dedicated route. Copy-link button now emits the new/dashboard/documents/[id]URL.RecentFactsaccepts alimitprop (defaults to 8; Trust Dashboard uses 4 for “Recent evidence”).- Contradiction navigation across the app (
FactInspectorModal,ContradictionsBannercopy-link,NotificationBelledge clicks) now lands on/dashboard/knowledge/constitution?contradiction=<id>directly, skipping the redirect hop. - Fact deep-links (
scout-fact-sheet,FactInspectorModalcopy-link,NotificationBellfact clicks,contribution-confirmation, onboarding redirect, dashboard root redirect, campaigns/[token]/workspace redirect, demo page links) point at/dashboard/knowledgedirectly.
Removed
src/app/dashboard/pot/page.tsx(orphaned by the/dashboard/knowledgerewrite; sub-routes/pot/agents,/pot/campaigns,/pot/meetingsremain — they’re separate features).src/app/dashboard/activity/page.tsx(replaced by the new/dashboard/knowledge/activitysub-route; the old URL 308-redirects).src/components/pot/pot-dashboard.tsx,src/components/pot/pot-documents.tsx, andsrc/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 likeuploaded_by_contributor_idorpot_scorevia 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.*, andconsumption.*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 consumesuseLanguage().
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 threeHoursTabIneligiblereasons 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 —
syncQuotasToSciPotalways only passedmax_monthly_tokensto SciPot, and SciPot’s ownmax_documents_per_pot: 50default 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.
getCapMinutesno longer checksbonusMeetingMinutesExpiresAt; bonus always counts. The column stays on the schema (NOT NULL onmeeting_hours_topup, nullable onsubscription) for historical rows, but is no longer load-bearing. - Eligibility check simplified. Dropped the
period_end_too_soonreason fromcanBuyHoursTopup(no anchor to protect anymore). The helper now rejects only onno_sub,cancelling, andoverride_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 + minutesPurchasedSQL 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-statusresponse shape dropsbonusExpiresAt(no longer meaningful).
Note for operators
If you previously had customers refused byperiod_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 theSTRIPE_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’sres.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
bonusExpiresAttoadminGrantedUntilvia a newgetEffectivePeriodEndhelper. Same atomic-credit semantics as paid subs; the bonus disappears from the quota read path when the grant cliff passes. getEffectivePeriodEnd(sub)helper intopup-eligibility.ts— returnscurrentPeriodEndfor Stripe subs and falls back toadminGrantedUntilfor 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. TheisPaidgate widened to acceptadminGrantedPlan === truealongside 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-planvalidation 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 aborder-primaryhighlight and “Recomendado” badge on both tabs. - Inline “Buy extra hours” panel in
/dashboard/settings/meetingswhenever 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-statusused by the web import-flow pre-check (read-only, no Stripe sync). - Shared
formatPricehelper insrc/lib/billing/format.tsusingIntl.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()insrc/lib/meetings/quota.tsnow returns the effective cap (plan + non-expired bonus) plus a breakdown ofplanMinutes/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

