Conversation
fix(ai): resume auto-reply through service-role client
Integrar conhecimento verificado da NOVYRA
feat(whatsapp): enforce 24-hour customer service window
Adds a manually selectable Portuguese catalogue, persists the chosen locale in a first-party cookie, and localises the existing WhatsApp 24-hour service-window interface.
New 'Avaliação' tab in /agentes (admin+): runs the golden-set cases and customer-simulation personas one at a time, using the account's own already-configured AI key — no shell/env vars needed. Each run shows its score, criteria breakdown, and exactly which tools were called, so tool-decision regressions are visible without leaving the browser. - GET /api/ai/eval/cases — metadata only, no LLM calls. - POST /api/ai/eval/run-one — runs exactly one case/persona by id, resolved server-side against the fixed known sets (never accepts case content from the client, so it cannot be redirected at arbitrary text on the account's own key). - New aiEvalAccount rate limit (3/hour) — each run is dozens of real model calls against the account's own spend. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- learnings.md + a short protocol appended to AGENTS.md: read at the start of a session, append real lessons at the end, escalate to a durable rule if the same mistake repeats. Seeded with 5 real lessons from this session (git-sync between two Claude Code sessions, external-catalogue schema drift, colour gender agreement, the two separate tool_key CHECK constraints, migration timestamp collisions, and the GRANT-vs-RLS bug). - New src/lib/ai/pricing.ts: real published USD/1M-token pricing for gpt-5.4-mini and claude-haiku-4-5 (checked August 2026), returns null for any unpriced/custom model rather than guessing. - New ai_configs.usd_to_mzn_rate (editable in Configuração, seeded at 63.91, the real rate at time of writing) — /api/ai/usage now computes real cost per model and shows it in Metical in the Utilização tab, alongside the USD figure and a note when a model has no known price. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The exchange rate used to convert token spend into Metical (shipped in d05320d) was a manually-typed settings field, which drifts stale the moment the real rate moves. Replace it with an automatic fetch from BCI's public daily exchange-rate page (bci.co.mz/cambio), cached on ai_configs for 6 hours to avoid hitting their site on every dashboard load, with a three-level fallback (fresh cache -> live BCI fetch -> stale cache -> hardcoded default) so a network hiccup or markup change never breaks the usage page. Settings now shows the rate read-only, with a "last updated" timestamp, instead of an editable input -- editing it locally would have silently fought the next automatic refresh. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The GET handler returned a generic "Failed to load AI configuration" on any select error but never logged what actually went wrong, making a live report of that message undiagnosable from server logs alone. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Audited the whole customer-facing pipeline (reply cap/handoff, tool
calling, guardrails, prompt) before opening the agent to real
customers. The core pipeline (buffering, atomic reply-slot claim,
webhook idempotency, handoff notices) checked out safe. These fixes
close the real gaps that surfaced:
- dispatchPendingActions no longer aborts the whole photo batch when
one WhatsApp media send fails -- each send is isolated, and the
customer gets photos 1 and 3 even if photo 2 failed, instead of a
generic apology and silently dropped remaining photos. A new
MEDIA_SEND_FAILURE_NOTICE only fires when every send in the batch
failed; a partial failure is just logged.
- New stock- and size-honesty system prompt rules: the agent now
checks a product's real stock value before implying it's available,
and admits honestly when size data isn't in the catalogue instead of
guessing.
- New prompt clause for a brusque/impatient (but not complaining)
customer: stay calm, don't mirror tone, and don't hand off on tone
alone.
- buildSearchVariants gains an opt-in size-cue detector ("tamanho M",
"numero 38") so a customer asking by size doesn't silently get zero
matches -- gated behind an explicit size-indicating word so it can't
flood every search the way a naive short-token match would.
- Trimmed noisy DOMException dump in the exchange-rate BCI-fetch log.
- Three new catalog eval golden-set cases (out-of-stock, size
fallback, rude-tone) exercising the new rules against the existing
fixture-tools harness.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…t gap Investigated the account owner's concern that no user can configure the agent's tools for their own business -- everything was fixed in code, even though every account on this platform is a different business. Two concrete bugs surfaced alongside that architectural gap: - The live auto-reply path always calls buildSystemPrompt with an empty knowledge array (by design -- knowledge only reaches it via the search_knowledge tool call), so the "trust these excerpts, don't guess" framing that exists for the draft path never reached real customer conversations. search_knowledge's description and JSON result now carry that same framing directly, since that's the channel the live path actually uses. - get_style_opinion (a fashion-styling tool) was enabled by default for every new account regardless of business type, unlike every other business-specific tool (add_tag, create_deal, schedule_visit), which require explicit opt-in. Flipped to match that pattern. Also added two prompt rules for cases the agent had no guidance on: a message too vague for any tool to resolve (ask a natural clarifying question instead of a canned line), and a capability that's simply not enabled for this account (never claim a tool it doesn't have, or a tool by name). For the architectural gap itself: agent_tools gains a free-text `instructions` column, editable per tool in Agentes -> Ferramentas, appended to that tool's built-in description at request time. This is the cheapest lever toward "every account configures its own tools" -- letting any business tailor a fixed tool's behavior (e.g. "we don't schedule visits on Sundays") without a code change, without building a full custom-tool system. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Found in a real production conversation: the customer asked for a styling opinion and the reply included this, sent verbatim as if it were the message itself: "Veja estas opções:\n\n[Opção interactiva no WhatsApp]\nSeleccione este produto abaixo...\n\n[Opção interactiva no WhatsApp]..." buildConversationContext annotates past media/interactive messages with bracketed notes like this so the model can read its own history -- they were never meant to be reproduced. The model picked up the pattern from its own prior turns and echoed it back as literal reply text, which is about as clear a "this is obviously a broken robot" moment as a customer can get. Two layers: a new prompt rule explicitly tells the model these brackets are for its own understanding only, and guardrails.ts now blocks (and hands off) any reply that contains one of these markers, the same mechanism already used for leaked [[CONTROL]] tokens. The marker list moved into its own history-annotations.ts module rather than being exported from context.ts directly -- auto-reply.ts's tests mock the whole context module, which would have silently broken guardrails.ts's import of it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Reviewed real conversation history and found three concrete conversational gaps in the same "Catalogue selling rule": - "Nao tem mais tipos?" got the exact same 3 products resent, verbatim, twice in one conversation. The old wording actually licensed this: "repeat all prior options unless the customer asks for more choices" reads backwards -- asking for more should mean showing something different, not resending the same list. - "Tem mais cores disponiveis?" (about a specific conjunto already shown) got three completely unrelated products back instead of colour variants of the item actually being discussed. - A customer asking "quanto custa" / "so quero o preco" three times in a row got the same qualifying question (compression preference) repeated three times, never a price, until a human intervened. Rewrote the rule to require genuinely different results when asked for "more", resolve colour/variant follow-ups against the specific item already in context, and drop a qualifying question once the customer has answered it or pushed back, answering with the best available info (e.g. a price range) instead of asking again. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…d with the tool loop Followed up on a full architecture audit (agent runtime vs. a sophisticated prompt layer) with the concrete gaps it surfaced: no way to scope agent behaviour per business objective without growing the one shared prompt scaffold, no sampling-temperature control, and three of the AI surfaces (draft, Playground, operator-reply) never used the real tool-calling loop the live auto-reply bot runs, so what an agent tested in the Playground did not reflect what a customer actually got. - New wacrm.skills table: a named bundle of an objective prompt fragment plus a subset of the existing 8 tools, scoped per agent. Purely additive: an agent with zero skills configured behaves exactly as before. Wired into auto-reply.ts prompt composition and tool permission narrowing (agent_tools stays the ceiling; handoff_human is exempt from narrowing, since it is the safety valve, not a business capability). Minimal CRUD UI under Agentes -> Skills. - ai_configs gains an optional temperature column (null means provider default, unchanged behaviour for every existing account), threaded through generate.ts into both provider adapters, with a UI toggle. - draft and Playground now run the same tool-calling loop as auto-reply, scoped to PREVIEW_SAFE_TOOL_KEYS (catalogue/knowledge/ style-opinion search), never a mutating tool (create_deal, add_tag, schedule_visit), since a draft or Playground turn can be discarded without ever being sent. Playground has no real conversation or contact, so its tool calls skip the per-call agent_tool_calls telemetry insert (see the conversationId guard in tools/index.ts). Migrations are included but not applied to any database. Run them via your normal Supabase migration flow before deploying. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The usage dashboard showed "preco desconhecido" for gpt-5.4-nano since it was never added to MODEL_PRICING. Sourced current OpenAI pricing (0.20 dollars per million input tokens, 1.25 per million output) from OpenRouter and Requesty. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ity, memory, overview)
Follow-up to the architecture audit and its critical evaluation: the
single ai-config.tsx form conflated identity, behaviour, credentials,
commercial strategy and handoff destination into one screen, with no
visibility into what the agent actually had available. Split it into
one shared config hook plus per-concern tabs, matching the reference
architecture from the evaluation: Overview / Identity & Behaviour /
Skills / Tools / Knowledge / Memory / Security & Handoff / Model &
Runtime / Playground.
Deliberately excluded, per the same evaluation: behaviour sliders with
real runtime effect (would require decomposing the fixed prompt
scaffold in defaults.ts -- a Context Builder change, not a UI change)
and any skill-selection/routing mechanism (skills already fold into
the prompt as structured reading material for the model's own
judgement, not as router input).
- New agent identity fields (name, role, language, description) on
ai_configs -- optional, only change buildSystemPrompt's opening line
when set.
- Skills gain objective / when_to_use / when_not_to_use, rendered as
labelled sections in skillsPrompt() so the model has clearer material
to reason over -- no selection logic added, every enabled skill is
still always active together, exactly as before.
- Knowledge documents gain a free-text type label and a status
('active'/'archived'). Archiving is UI-facing metadata only in this
pass -- retrieveKnowledge/the match_ai_knowledge_* RPCs are
unchanged, so an archived doc still surfaces in retrieval; excluding
it would mean editing the retrieval runtime, out of scope here.
- New Segurança & Handoff tab: the two existing config fields (reply
cap, handoff destination) plus a read-only mirror of the real
handoff/guardrail rules in route.ts/guardrails.ts. Not editable, by
design -- a business admin should never be able to switch off a
safety rule through this screen.
- New Memória tab: view + delete over contact_memories. No
categorization, no change to the extraction logic in
contact-memory.ts.
- Playground now returns an ephemeral per-turn execution trace (active
skills, tools called, knowledge sources used, guardrail result) --
never persisted, since there is no real conversation for
agent_traces to attach to. Tools tab shows last-used timestamp and
which skills reference each tool.
- Retired the monolithic ai-config.tsx (738 lines, only ever used from
this one page) in favour of use-agent-config.ts (shared fetch/save
state) plus agent-identity.tsx / agent-runtime.tsx /
agent-security.tsx / agent-overview.tsx.
Three additive, nullable-column migrations; none applied to any
database by this change.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…d in interface audit
Ran a full better-interface (accessibility/layout/writing/typography/
colors/ui) audit of the Agentes page against the real code (no live
render -- auth is against a production-connected Supabase instance,
so signing in to screenshot was avoided). Presented two redesign
options; this implements the chosen one plus every finding the audit
surfaced.
- New AgentBuilderShell: replaces the flat 13-item horizontal tab bar
with a grouped sidebar (Visao Geral / Configurar / Controlar /
Testar / Observar), matching the grouping the flat tab list had no
way to express. Modeled as navigation (buttons + aria-current, not
an ARIA tablist) and copies the primary app sidebar's own mobile
drawer mechanics (translate-x, backdrop, Escape, scroll lock) rather
than inventing a new pattern. Every section stays mounted (hidden
via the `hidden` attribute) when inactive, so switching away from
Playground no longer drops the test conversation.
- Fixed the two HIGH accessibility findings: icon-only delete buttons
(skills, memories) had no accessible name; the API-key show/hide
toggle had tabIndex={-1}, making it a pointer-only control (a
pre-existing bug inherited from the old ai-config.tsx when it was
split up).
- CardTitle gains an opt-in `as` prop (defaults to "div", unchanged
everywhere else) so a title can render as a real h3. Applied across
every CardTitle in the Agentes tree -- the page had almost no
heading outline for assistive tech, one root cause (the shared
div-only component), thirteen call sites.
- Playground's execution-trace disclosure now reports aria-expanded.
- Visao Geral: replaced seven border-b divider rows with two spaced
groups; unified max-w-2xl/max-w-3xl inconsistency.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Improves catalogue retrieval, product presentation, conversation catalogue state, media handling and AI category reclassification.
CATEGORY_ALIASES/COLOR_ALIASES lived as two separately hardcoded (and already drifted) constants in agent-search.ts and search.ts, baking one tenant fashion vocabulary (LC Fitness) into the shared retrieval and ranking engine. Any other vertical (car rental, clinic, etc) got no category/colour aliasing at all, and could not get any without a code change. Adds wacrm.catalog_taxonomy_terms (account_id, kind, canonical_value, aliases) and src/lib/catalog/taxonomy.ts, which loads an account own taxonomy and falls back to a single consolidated default list (the old two divergent copies, merged) only for accounts with nothing configured yet. agent-search.ts and search.ts now take the groups as a parameter instead of importing hardcoded constants; every existing call site keeps its old default behaviour via default parameters. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
src/app/api/meta/catalog-feed/route.ts resolved its one Meta Commerce Manager feed by ilike-matching a catalog_sources row named literally 'Base LC Fitness', with no account_id filter at all and no authentication on the public GET endpoint. It could not serve a second tenant without a code change, and if any other account ever named a source the same thing, this endpoint could serve the wrong tenant catalogue to the public internet. Adds catalog_sources.meta_feed_token (256-bit, built from two gen_random_uuid() calls so no extension dependency), and a new /api/meta/catalog-feed/[token] route that resolves a source only by its exact opaque token -- never by name, never by an account_id supplied by the caller. The CSV builder (src/lib/catalog/meta-feed.ts, extracted from the old route) uses the source own configured name for the brand/filename instead of a literal 'LC Fitness' string. The old fixed URL now only 308-redirects to a token configured via LEGACY_META_FEED_TOKEN (set by operators during migration), and otherwise 404s -- it has zero knowledge of any tenant. Also wires the settings UI (database-integrations.tsx) to show each connected source own feed URL with a copy button, and to select meta_feed_token in the sources API so that URL is available to show. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
buildSystemPrompt() in defaults.ts is the shared scaffold every
tenant on the platform gets, regardless of vertical. It unconditionally
included a 'Personal styling rule' (body, fitness habits, style
preference wording, referencing get_style_opinion and 'the brand') --
fashion-retail language a clinic or car-rental tenant would also
receive even though it never applies to them. The 'Image handling
rule' kept its useful generic mechanism (photo -> describe -> search
catalogue) but dropped the word 'garment' for 'product'.
The styling rule itself was not deleted -- it moved verbatim into a
new LC Fitness Skill ('Consultoria de Estilo'), seeded by migration
together with LC's own category/colour taxonomy data (including
'pantalona', previously unsupported by the hardcoded core list --
proof the mechanism works through configuration, not a code change).
Skills already only apply to the account/agent they are configured
for, so this is a behaviour-preserving move for LC, not a new
capability.
Also appends a learnings.md entry on the actual root cause of the
'category: null' reports for LC products (a missing settings-UI field
for catalogCategory, not the taxonomy/matching layer -- fixed in the
previous commit alongside the feed-token settings screen).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The 'Reclassificar tudo com IA' vision prompt in classify/route.ts had a fixed instruction listing fashion categories (legging, top, camisola, t-shirt, ...) in Portuguese for every account, regardless of vertical. buildClassificationSystemPrompt(knownCategories) now builds that instruction from the calling account own wacrm.catalog_taxonomy_terms rows (loadAccountCategoryTerms -- deliberately no fallback to the generic defaults used by search, since leaking LC's fashion vocabulary into another tenant's classification prompt would defeat the point). An account with nothing configured still gets a fully working, domain-neutral classifier that proposes its own category from the image instead of matching a suggested list. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The setting was already fully per-account configurable end-to-end (ai_configs.auto_reply_max_per_conversation, /api/ai/config, the Agentes -> Seguranca UI) -- the only real blocker for an account like LC Fitness that legitimately needs a longer bounded auto-reply run was the hard CHECK constraint capping it at 20. Raises the DB constraint, the API clamp and the UI max in lockstep; the protection itself is unchanged, only its ceiling. LC can now be configured up to 30 (or any bounded value) directly in Agentes -> Seguranca, no code change needed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
loadCatalogTaxonomy() still fell back to DEFAULT_CATEGORY_GROUPS/ DEFAULT_COLOR_GROUPS (legging, camisola, top, macacao, sapatilha, ...) whenever an account had no configured taxonomy or the lookup failed. That was still business-specific hardcode sitting in generic runtime code, even though it was consolidated from two copies into one. LC already gets this exact vocabulary through its own tenant migration (20260813093000_lc_fitness_taxonomy_and_style_skill.sql), which is the correct place for it. An account with no configured taxonomy (or a failed lookup) now gets empty category/colour groups, not a hardcoded list. This does not turn off matching: buildSearchVariants and categoryMatches/colorMatches already fall back to plain substring/token matching on the raw requested text when no alias group applies -- that generic textual matching keeps working with zero configured taxonomy, just without synonym/gender-inflection expansion. search.ts no longer imports any default vocabulary either -- its categoryGroups/colorGroups parameters now default to empty arrays. Tests updated: taxonomy.test.ts asserts LC's own account gets LC's aliases, a car-rental account gets its own (isolated) aliases, an unconfigured account gets empty groups (never LC's), and a DB error also yields empty groups, never LC's. search.test.ts now proves the same generic mechanism by passing explicit sample groups instead of relying on an implicit default, plus new cases proving no expansion happens with none supplied. agent-search.ts needed no code change -- its matchers already treat taxonomy as a plain parameter. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tools buildSystemPrompt()'s universal scaffold unconditionally included the Catalogue selling rule, Stock honesty rule, Size honesty rule and Image handling rule -- product/stock/size/photo instructions every account on the platform received even a support-only or booking-only tenant with no search_catalog/send_product enabled at all. Extracts them into catalogueCapabilityPrompt(), injected by buildSystemPrompt only when a new hasCatalogueCapability flag is true. No new framework -- one function, one boolean, computed from the account's own already-loaded tool permissions (search_catalog || send_product) at each of the 6 call sites (auto- reply, draft, playground, operator-reply, and the 2 eval helpers). draft/playground/operator-reply had to move their existing permission- loading block to run before buildSystemPrompt instead of after, since the flag has to exist before the prompt is built; no new DB calls were added, the same loadAgentToolPermissions call just runs earlier. operator-reply computes the flag from the account's raw permissions (matching how the other three routes do it), not from its own further- narrowed read-only tool subset, so LC's prompt is unchanged from before this commit. LC has both tools enabled account-wide, so this is behaviour-preserving for LC on every call site; a support-only account now correctly never sees product/stock/size/photo instructions it has no tool to act on. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
An admin can now create/edit/disable/delete their own category and colour vocabulary (wacrm.catalog_taxonomy_terms, already in place from the previous SaaS-hardening branch) entirely from the UI -- no SQL, no migration, no code change, no redeploy. New endpoints: GET/POST /api/catalog/taxonomy, PATCH/DELETE /api/catalog/taxonomy/ [id], all scoped by the caller own account_id. GET also returns an approximate product count per term so deleting one is an informed decision. Adds two small reusable UI primitives this needed anyway: CollapsibleEditor (view-mode summary, click to reveal an edit form, Guardar/Cancelar) and AttributeSelect (a searchable category/colour picker with inline "+ Criar" instead of a free-text input, so 'pantalona'/'Pantalona'/'PANTALONA' cannot become three different categories). classify/route.ts now snaps the vision model output to the account own canonical value when it matches one of the account configured aliases (the AI can still propose a brand-new category when nothing matches). Adds jsdom + @testing-library/react + @testing-library/user-event as dev dependencies -- the repo had no way to test interactive component behaviour (search/select/create-new, expand/collapse) before this. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The bulk uploader used a bare <input type="file" multiple> ('Choose
Files / No file chosen'). BulkUploadDropzone replaces it with a real
drop zone: drag & drop, click-to-pick via an accessible <label>
wrapping a visually-hidden input (native keyboard/screen-reader
behaviour, no hand-rolled focus handling), non-image drops filtered
out client-side.
BulkItemCard shows each photo per-item state individually --
uploading, 'A analisar com IA...' while classifying, a 'Pronto' or
'Falta informação' badge, and its own error text -- instead of one
undifferentiated grid, and uses AttributeSelect for category/colour
instead of free text.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ive AI reclassify Catálogo now defaults to Produtos (internal catalogue). External integrations (REST API + external Supabase, previously two of three equal tabs) move into one 'Integrações externas' tab, clearly labelled Beta with the same amber-pill pattern already used for Flows, and introduced by copy explaining it is optional -- a new account is never steered toward configuring an external database just to use the agent. Nothing about those integrations was removed or altered. ProductCard: view mode shows photo/name/price/category·colour/state only, a 'Pronto'/'Falta informação' badge, and category/colour editing now goes through AttributeSelect instead of free text; unchanged otherwise (Editar expands, Guardar/Cancelar collapses back). 'Reclassificar tudo com IA' becomes 'Organizar produtos com IA' behind a real confirmation dialog (not a browser confirm()): shows how many products will be reviewed, and a choice between 'Preencher apenas campos vazios' (default -- never touches a category/colour/description a person already filled in) and 'Rever todos' (explicit warning that existing data may change). Progress and a final summary (classified / needs review / failed, failures listed by name, never hidden) render in the same dialog. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Every Skill (and every Tool) rendered as a permanently-open card -- name, objective, when-to-use/not, instructions, tool checkboxes all visible at once for every row, regardless of whether it was being edited. With more than a couple of skills configured this was a very long page. Both now use the shared CollapsibleEditor: collapsed shows a summary (name, ACTIVA/INACTIVA, objective, tool count for Skills; icon, title, last-used/used-by for Tools), click to expand into the actual edit form, Guardar/Cancelar collapses back with a toast and an updated summary -- one row open at a time is not enforced, but nothing is open until the admin asks for it. Skills' enable Switch and Tools' enable Switch both moved out of the clickable header into CollapsibleEditor's new headerActions slot (a sibling of the toggle button, not nested inside it) so flipping a switch never also opens the edit form -- nesting an interactive control inside the header button would have been invalid markup either way. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ager
'Pantalona' / 'pantalonas, calça pantalona, wide leg' / 'Preto' /
'preta, black' were LC's own example values shown as input placeholders
to every account, including a car-rental or clinic tenant that will
never see anything resembling their own business in the form they use
to create their first category. Not a functional leak (nothing reads
these strings), just an example that should not carry one tenant's
vocabulary into a generic UI. Replaced with sector-neutral placeholder
text ('Ex.: Categoria principal' / 'sinónimo 1, sinónimo 2' / 'Ex.: Cor
principal').
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Owner
|
Thanks for sharing this. Per CONTRIBUTING.md this repository is a template: forks are expected to diverge, and upstream only takes small, scoped fixes (security, correctness, docs) opened against current Same note as on #475/#476: the private |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
What changed
Test plan
npm run typecheckclean.npm run lint— no new errors beyond the pre-existing backlog.npm run buildsucceeds.Related