merge - #6
Merged
Merged
Conversation
- Add missing API_SETUP.md documenting env vars referenced by root/api CLAUDE.md - Fix ui/CLAUDE.md auth flow to describe Firebase Auth (was stale JWT refresh-token flow) - Correct Bills/OCR status from stub to functional 3-step wizard in root + ui CLAUDE.md - Reconcile Repository<T> docs in api/functions/CLAUDE.md: remove non-existent getAll(), mark hard delete()/deleteBatch() as internal/cascade-only per soft-delete-only decision
- Add money.util.ts (decimal.js, half-up to 2dp) with billAmount/sumMoney helpers, plus a UI mirror in money.ts (no new UI dependency) - Apply across reports.service.ts aggregations and the billings/bills UI amount calculations so API and UI agree to the centavo - Add property-based tests for calculateTrueReading/getCumulativeOffset/ validateMeterRollback covering 0-3 meter resets, submeters, and the reset-boundary rollback exemption (1e) - 1d: verified the 3%/5% consumption tolerance checks operate purely on raw consumption (kWh/m³), never on rounded peso amounts, so the new rounding does not affect tolerance boundaries — no code change needed
…ase 2A, WIP) Wires up Firestore+Auth emulators, API dev:emulator, and a --mode test UI build/preview for E2E (decisions/20260611_emulator-for-e2e-testing.md, untracked per .gitignore). Login through reading-creation/auto-billing now pass; billing cycle discovery still fails (timezone-related, root cause + remaining steps in ui/e2e/STATUS.md). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The sqlite+transformers-based rag.ts/rag-query.ts implementation is superseded by the standalone rag-tool (coding-projects/rag-tool), so drop the in-repo copy, its test, the now-unused embedding/db deps, and requirements.txt, and repoint CLAUDE.md at the new tool.
Add concurrency groups to cancel superseded PR runs, add a 10-minute timeout, raise npm audit to fail only on high/critical, and collapse the separate test/deploy jobs into one gated job so deploy steps reuse the already-installed/built artifacts instead of re-running from scratch. UI CI also skips the Playwright browser download (unit tests only run here) and switches the Vercel step to the CLI directly.
Add a third compose service for the mobile Vite web preview (port 5174), and enable CHOKIDAR_USEPOLLING on api/ui/mobile so file edits made on a Windows host are reliably picked up through the WSL2/ VirtioFS bind mount (native fs.watch was silently missing changes). Also documents the required network_security_config.xml step for a freshly regenerated Android project, and updates the docker/terminal setup instructions across CLAUDE.md, CONTRIBUTING.md, and README.md.
…ipts Stop ignoring api/functions/package-lock.json (mirrors ui/mobile, which are already tracked) so CI's npm ci is reproducible. Also add mobile's vite-plugin-svelte patch bump, ui's SKIP_PLAYWRIGHT_INSTALL guard for the docker-compose UI container's prepare script, and run ui dev against the staging mode by default.
Add ImageUrlSchema, which only accepts https:// URLs to a public host or data:image/* URIs, rejecting localhost/private/link-local/metadata- endpoint hosts. A user-supplied image_url was previously validated only as "a URL", letting a server-side fetch probe internal services or the cloud metadata endpoint (169.254.169.254). Wire it into the billing-cycle, bills, and image-extraction OCR DTOs.
Move the tenant-count-vs-cap check out of the validator (a plain read before the write) and into the same Firestore transaction that creates or updates the tenant doc. Previously two concurrent requests could both read a stale pre-write count, both pass validation, and both write, letting a property exceed its tenant cap. Firestore retries the transaction on write conflict, so the losing request now re-reads the updated count and gets the same capacity error instead of a raw conflict. Adds CachedRepository.cacheCreatedItem/cacheUpdatedItem so the cache can be updated for writes made inside the transaction rather than through repo.create/update, and hardens applyFilters to reject unsupported range-filter objects instead of silently mis-comparing.
…eation Both readings/batch and billing-cycles/batch previously validated the whole array up front and threw on the first bad item, aborting the entire batch. Validate and create each item independently instead, so one invalid item (duplicate month, main-meter rejection, anomaly, duplicate meter_group_id, etc.) is reported per-index in `failed` and every other valid item still gets created. Also closes a TOCTOU race in auto-billing: concurrent requests for the same meter_group+property +month can no longer both create a reading/billing, since the transaction now does a deterministic txn.create() against a READING_LOCKS doc and Firestore rejects the loser with ALREADY_EXISTS (surfaced as 409). Updates the UI/mobile API clients and the readings page to handle the new BatchCreateResult<T> shape.
Extract getVersionsSource/getCumulativeOffset/trueReading/ resolveCurrentVersion into ui/src/lib/utils/true-reading.ts, mirroring the API's resolveVersionsSource/calculateTrueReading so submeter properties (which track their own reset history on Property.meter_groups[entry]) display correct all-time totals instead of the previous MeterGroup-only offset calculation. Wire it into the readings and billings pages, memoize reading/property/meter-group lookups into Maps instead of re-scanning arrays per row, and switch the billings-by-cycle map to SvelteMap for reliable reactivity. Also adds a "straggler" modal on the billings page to fold a late-arriving reading pair into an already-created billing cycle (creates the billing, then PATCHes the cycle's billing_ids/ billing_consumption to include it), since PATCH replaces the whole billing_ids map rather than deep-merging.
Extract findMeterGroupById() instead of repeating the electricityMeters.find(...) || waterMeters.find(...) pair at each call site.
Extract fetchReportContext() so buildJoinedData and getConsumption share the cycles→billings→properties→meter-groups fetch instead of duplicating it, index cycles by billing id in a Map instead of an O(n) .find() per billing, replace `any`-typed filter helpers with the real SearchFilter/RangeFilter types, and drop leftover debug console.log calls.
…vice ocrBill previously called geminiLib.extractBillData directly, bypassing the image_url validation and 422-on-extraction-failure handling that POST /image-extraction/billings already has. Delegate to ImageExtractionService.extractBillingFromImage instead so both endpoints share one source of truth for OCR extraction. Also remove validate-dto.middleware.ts — dead code with no remaining callers.
Extract shapeUserResponse() instead of repeating the same object literal in getMe and updateMe.
Pre-build meter-group-owner and normalized-room-name maps once per batch validate call instead of re-scanning allProperties with .find() for every item — O(n) per conflict check becomes O(1).
The READING_LOCKS doc introduced for auto-billing's TOCTOU fix otherwise outlives the reading it was created for, permanently blocking a legitimate delete-then-recreate within the same meter_group+property+month. Cascade delete now releases the lock in the same transaction as the soft-delete; cascade restore re-claims it via txn.create() (not set()) so two soft-deleted readings that happened to share a slot can't both come back active — the losing restore gets a clean 409 instead of a silent double-claim. Also batches list-cache invalidation and id-cache cleanup with Promise.all instead of sequential awaits, and swaps an O(n) foundReadingIds.includes() scan for a Set lookup.
Mounts every feature router behind authMiddleware (mirroring the mount order in src/index.ts) and asserts each protected GET/POST route returns 401 with no or a malformed Authorization header — a regression guard against a route accidentally being mounted before authMiddleware or missing it entirely, which per-feature test suites wouldn't catch since they only exercise their own router in isolation.
copy-staging-to-emulator.ts does a read-only, one-way copy of utilitool-staging Firestore data into the local emulator (project utilitool-test) so E2E/shadow-replay runs can exercise real-shaped data instead of only synthetic fixtures — refuses to run unless EMULATOR_HOST is set and hardcodes the destination project id so it can never be pointed at a real project. shadow-replay.ts runs the actual report/validator business logic against whatever Firestore the app is pointed at and dumps a JSON snapshot, meant for diffing before/after output of this branch's changes to catch silent behavior drift; it refuses to run unless FIRESTORE_EMULATOR_HOST is set. ui/e2e/global-setup.ts gets a SEED_FROM_STAGING=true flag to skip its destructive Firestore clear when a staging snapshot has already been imported.
Throw at module load if VITE_API_BASE_URL isn't https:// in a production build, closing the cleartext-traffic path the network security config in mobile/BUILD.md also blocks at the OS level. Also extract buildHeaders() so the 401-retry path can't drift from the initial request's header construction (it was reconstructing the auth header manually instead of reusing the same header-building logic).
… wizard Main-meter properties without a reading at the meter group's current version now appear in the capture wizard (badged "Seed (baseline)") and submit via POST /readings/seed individually, instead of requiring a separate baseline-seeding form on the Settings screen — mirrors the web Readings page's shouldSeedReading() auto-detection. Seed and regular readings are submitted with Promise.allSettled/batch respectively and per-item failures are surfaced with the property name instead of aborting the whole submission. Removes the now- redundant seed form from Settings.svelte, and Billings.svelte's getCycleBillings() takes the already-available cycle object instead of re-finding it by id.
Adds a tool-calling chatbot (Groq/Ollama Cloud via a shared OpenAI-compatible client) scoped to the authenticated user's own properties, readings, and billings, plus a per-tenant llm-config feature to store the provider/model and an AES-256-GCM encrypted API key. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Mounts a global ChatWidget on all protected routes and adds a Settings page for configuring the chatbot's LLM provider, model, and API key. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Updates root, api, and ui CLAUDE.md navigation docs to cover the new /chatbot and /llm-config endpoints, ChatWidget, and settings page added in the prior two commits. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A documentation audit found several places where CLAUDE.md/README claims had drifted from the code they describe (code is treated as source of truth). Fixes: - mobile/CLAUDE.md: add the lib/utils/ directory (auth-errors, format, timestamp, utility-colors, billing-cycle.util) and the billing-cycles.ts API module, both actively used but missing from the file map. - api/functions/CLAUDE.md: remove the "Stub & Incomplete Features" rows for model/, ocr/, and payment/ — these folders no longer exist. - CLAUDE.md, README.md: correct the CI/CD section — the UI's Vercel deploy is configured to trigger on push to main as well as on pull requests (per the workflow's own comment, this push-to-main deploy is what's actually serving as "staging"), not PR previews only. - ui/CLAUDE.md: reword the Settings/Users page status from "Partial" to reflect what's actually there (a complete create-user flow with role select, validation, and partial-failure handling) and what's actually missing (listing/editing existing users); add the four format.ts exports (getReadingUnit, formatReading, formatLongDate, parseDate) that were undocumented. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
An audit comparing every feature's *.swagger.ts / swagger.config.ts
schemas against its *.dto.ts Zod validators (the DTO is the runtime
source of truth) found several places where the documented request/
response shape no longer matched what's actually validated. Fixes:
- property: CreatePropertyRequest/UpdatePropertyRequest/Property were
still documenting the old flat `meter_group_id: string` field from
before multi-meter support; replaced with the actual `meter_groups`
record (keyed by electricity/water, each {meter_group_id,
is_main_meter}) the DTO validates.
- reading: `property_id` is required by CreateReadingDTOSchema but was
entirely absent from Reading/CreateReadingRequest/UpdateReadingRequest;
added.
- llm-config: `apiKey` was documented as required, but the DTO makes it
optional (omitting it keeps the previously-stored key); fixed the
required array and documented the behavior.
- billing-cycle: added the missing `overdue_date` field to
BillingCycle/CreateBillingCycleRequest/UpdateBillingCycleRequest, and
added `minimum: 0` to billing_ids values to match the DTO's
`.nonnegative()` constraint.
- meter-group, property, reading, billing, tenant, billing-cycle: every
list-query DTO defines working `sortBy`/`sortOrder`/`archived` params
(plus `minimal` for meter-groups), none of which were documented as
swagger parameters on any of the six list endpoints; added all of
them.
Verified with `npx tsc --noEmit` (clean) after all edits.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
toLocaleString() produced locale-dependent grouping/decimals while mobile used toFixed(2), so the same reading value rendered differently across platforms. Standardize on fixed 2-decimal precision. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Previously a failed role write after account creation was only console.error'd, leaving an admin account with no role and no visible indication anything went wrong. Show a warning banner instead so the admin knows to retry from the users list. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
formatDate/formatDateTime in lib/utils/timestamp.ts shared names with ui's Date-based formatters in lib/utils/format.ts despite taking a different input contract (Firestore timestamp | string | any vs Date). Rename to formatTimestampDate/formatTimestampDateTime to make the contract explicit and avoid confusing future cross-project changes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR brings together UI, mobile, and API updates to support emulator-backed E2E testing, centavo-exact money handling, and a new “Insight” chatbot feature (LLM config + chat endpoint + UI widget), alongside several validator/service hardening improvements (notably batch operations and reading/billing correctness).
Changes:
- Add LLM provider configuration + authenticated chatbot endpoint, and mount a global chat widget in the UI.
- Introduce batch-create “partial failure” result shapes (
{ created, failed[] }) and improve reading/billing-cycle validation behavior (including duplicate-prevention via reading locks). - Add Playwright E2E harness using Firebase emulators + supporting dev/CI/docker workflow updates.
Reviewed changes
Copilot reviewed 112 out of 117 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| ui/svelte.config.js | Load Vite env for CSP/emulator connects |
| ui/src/routes/(app)/settings/users/+page.svelte | Add warning state for partial user creation |
| ui/src/routes/(app)/settings/llm-provider/+page.svelte | New LLM provider settings page |
| ui/src/routes/(app)/settings/+page.svelte | Add settings card for LLM provider |
| ui/src/routes/(app)/readings/+page.svelte | True-reading + batch-create partial failure UI |
| ui/src/routes/(app)/properties/+page.svelte | Refactor meter-group lookups + main-meter UX |
| ui/src/routes/(app)/bills/+page.svelte | Use money helper for totals |
| ui/src/routes/(app)/+layout.svelte | Mount global ChatWidget |
| ui/src/lib/utils/true-reading.ts | New true-reading helpers (version-aware) |
| ui/src/lib/utils/true-reading.test.ts | Tests for true-reading utilities |
| ui/src/lib/utils/money.ts | New UI money rounding helpers |
| ui/src/lib/utils/money.test.ts | Tests for UI money helpers |
| ui/src/lib/utils/format.ts | Reading/date formatting adjustments |
| ui/src/lib/types/llm-config.types.ts | New LLM config types |
| ui/src/lib/types/api.types.ts | Add BatchCreateResult type |
| ui/src/lib/firebase.ts | Connect to Auth/Storage emulators for E2E |
| ui/src/lib/components/shared/ChatWidget.svelte | New floating chatbot widget |
| ui/src/lib/api/readings.ts | Batch create returns BatchCreateResult |
| ui/src/lib/api/llm-config.ts | New llm-config API client |
| ui/src/lib/api/chat.ts | New chatbot API client |
| ui/src/lib/api/billing-cycles.ts | Batch create returns BatchCreateResult |
| ui/playwright.config.ts | Emulator-bootstrapped E2E webServers |
| ui/package.json | Adjust dev mode, prepare script, deps bumps |
| ui/e2e/STATUS.md | E2E phase status + known issue notes |
| ui/e2e/global-setup.ts | Seed/clear emulator state for E2E |
| ui/e2e/billing-happy-path.e2e.ts | Money-critical E2E happy-path spec |
| ui/CLAUDE.md | UI docs updates for new features/flows |
| ui/.env.test | UI env for emulator-backed E2E |
| requirements.txt | Remove sentence-transformers dependency |
| README.md | Add mobile dev workflow + docs tweaks |
| mobile/src/screens/ReadingHistory.svelte | Timestamp formatter rename usage |
| mobile/src/screens/CaptureReadings.svelte | Seed-reading support + batch result handling |
| mobile/src/screens/Billings.svelte | Timestamp formatter rename + refactor |
| mobile/src/lib/utils/timestamp.ts | Rename date formatting helpers |
| mobile/src/lib/api/readings.ts | BatchCreateResult typing + batch API changes |
| mobile/src/lib/api/client.ts | Enforce HTTPS API base in production |
| mobile/package.json | Update Firebase + vite-plugin-svelte versions |
| mobile/CLAUDE.md | Mobile docs updates for APIs/utilities |
| mobile/BUILD.md | Android network security config docs |
| docker-compose.yml | Add mobile service + polling watcher settings |
| CONTRIBUTING.md | Document mobile dev preview + docker workflow |
| CLAUDE.md | Root docs updates (RAG tool, staging deploy notes) |
| api/functions/src/utils/rag-query.ts | Remove in-repo RAG query implementation |
| api/functions/src/utils/rag-query.test.ts | Remove associated RAG query test |
| api/functions/src/utils/money.util.ts | Introduce Decimal.js money single source of truth |
| api/functions/src/utils/money.util.test.ts | Money util unit tests |
| api/functions/src/utils/image-url.util.ts | SSRF-safe image URL validation |
| api/functions/src/utils/image-url.util.test.ts | Tests for SSRF-safe image URL validation |
| api/functions/src/utils/cascade-delete.util.test.ts | Update cascade-delete tests for reading locks |
| api/functions/src/utils/batch-result.util.ts | Shared BatchCreateResult type |
| api/functions/src/migrations/shadow-replay.ts | Add emulator-only shadow replay script |
| api/functions/src/migrations/copy-staging-to-emulator.ts | Add staging→emulator copy script |
| api/functions/src/middlewares/validate-dto.middleware.ts | Remove legacy DTO middleware |
| api/functions/src/middlewares/auth-sweep.test.ts | Add auth gating sweep test |
| api/functions/src/lib/llm.lib.ts | New OpenAI-compatible LLM client wrapper |
| api/functions/src/lib/crypto.lib.ts | AES-256-GCM encrypt/decrypt helper |
| api/functions/src/lib/cached-repository.lib.ts | Typed filter application + cache helpers |
| api/functions/src/index.ts | Mount llm-config + chatbot routers |
| api/functions/src/features/tenant/tenant.validator.ts | Move tenant-cap enforcement into transactions |
| api/functions/src/features/tenant/tenant.swagger.ts | Add list query params docs |
| api/functions/src/features/tenant/tenant.service.ts | Transactional tenant-cap enforcement + caching |
| api/functions/src/features/reports/reports.service.test.ts | Add centavo-exact totals test |
| api/functions/src/features/reading/reading.validator.ts | Per-item batch validation with failures |
| api/functions/src/features/reading/reading.util.ts | Add reading locks + transactional create helper |
| api/functions/src/features/reading/reading.util.test.ts | Tests for true reading + rollback logic |
| api/functions/src/features/reading/reading.test.ts | Update mocks for txn.create/getByIds |
| api/functions/src/features/reading/reading.swagger.ts | Document batch partial failures + query params |
| api/functions/src/features/reading/reading.service.ts | Batch returns {created, failed} + restore fix |
| api/functions/src/features/reading/reading.service.test.ts | Tests for batch partial failures + restore behavior |
| api/functions/src/features/property/property.validator.ts | O(1) indexing for conflicts in batch ops |
| api/functions/src/features/property/property.swagger.ts | Add list query params docs |
| api/functions/src/features/meter-group/meter-group.swagger.ts | Add list query params docs |
| api/functions/src/features/llm-config/llm-config.swagger.ts | New llm-config swagger definitions |
| api/functions/src/features/llm-config/llm-config.service.ts | Encrypt/decrypt stored LLM API key |
| api/functions/src/features/llm-config/llm-config.route.ts | Add llm-config routes |
| api/functions/src/features/llm-config/llm-config.repository.ts | Store per-user LLM config doc |
| api/functions/src/features/llm-config/llm-config.model.ts | LLM config model |
| api/functions/src/features/llm-config/llm-config.dto.ts | LLM config DTO validation |
| api/functions/src/features/llm-config/llm-config.controller.ts | LLM config controller |
| api/functions/src/features/image-extraction/image-extraction.dto.ts | Use SSRF-safe ImageUrlSchema |
| api/functions/src/features/chatbot/chatbot.swagger.ts | New chatbot swagger definitions |
| api/functions/src/features/chatbot/chatbot.service.ts | Tool-calling chatbot orchestration |
| api/functions/src/features/chatbot/chatbot.service.test.ts | Chatbot orchestration unit tests |
| api/functions/src/features/chatbot/chatbot.route.ts | Chatbot route |
| api/functions/src/features/chatbot/chatbot.guard.ts | Regex jailbreak guard |
| api/functions/src/features/chatbot/chatbot.dto.ts | Chat request DTO + history limits |
| api/functions/src/features/chatbot/chatbot.controller.ts | Chatbot controller |
| api/functions/src/features/bills/bills.dto.ts | Bills OCR DTO uses ImageUrlSchema |
| api/functions/src/features/bills/bills.controller.ts | Delegate bill OCR to shared extraction service |
| api/functions/src/features/billing/billing.swagger.ts | Add list query params docs |
| api/functions/src/features/billing-cycle/billing-cycle.validator.ts | Batch partial failures + submeter validation |
| api/functions/src/features/billing-cycle/billing-cycle.validator.test.ts | Tests for submeter reset-boundary validation |
| api/functions/src/features/billing-cycle/billing-cycle.test.ts | Update batch-create expectations |
| api/functions/src/features/billing-cycle/billing-cycle.swagger.ts | Document batch partial failures + query params |
| api/functions/src/features/billing-cycle/billing-cycle.service.ts | Batch returns {created, failed} + ordering fix |
| api/functions/src/features/billing-cycle/billing-cycle.dto.ts | Use SSRF-safe ImageUrlSchema for OCR |
| api/functions/src/features/auth/auth.controller.ts | Factor shared user response shaping |
| api/functions/src/constants/collection.constants.ts | Add READING_LOCKS + LLM_CONFIG collections |
| api/functions/src/config/cors.config.ts | Allow 127.0.0.1 in localhost CORS pattern |
| api/functions/rag.ts | Remove old in-repo rag CLI |
| api/functions/package.json | Add Decimal.js, remove old RAG deps |
| api/functions/CLAUDE.md | Document LLM config + chatbot + docker notes |
| api/firebase.json | Add storage emulator config |
| API_SETUP.md | New env var documentation |
| .gitignore | Stop ignoring package-lock files |
| .github/workflows/ci-ui.yml | Combine CI+deploy, add audit, concurrency |
| .github/workflows/ci-api.yml | Combine CI+deploy, tighten audit, concurrency |
Files not reviewed (1)
- mobile/package-lock.json: Generated file
Comments suppressed due to low confidence (1)
mobile/src/lib/api/readings.ts:58
POST /readings/batchis validated server-side as a JSON array body (CreateReadingBatchDTOSchema isz.array(CreateReadingDTOSchema)), but the mobile client sends{ readings: [...] }. This will 400 at runtime once strict request validation runs, breaking batch capture on mobile.
…e*consumption Recomputing raw_amount from billing_rate * billing_consumption drops taxes, fixed fees, and tiering already reflected in the bill photo, and reintroduces float-rounding drift. Thread the value Gemini already extracts through ExtractedBillingData end-to-end instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
roundHalfUp2dp used Math.round with an EPSILON nudge, which still diverges from the API's Decimal.js half-up rounding on cases like 2.675, risking centavo mismatches between server and UI totals. Switch to decimal.js to mirror api/functions/src/utils/money.util.ts exactly. formatReading had regressed to toFixed(2) behind a dead duplicate return, dropping locale thousands separators. Restore toLocaleString with fixed 2dp formatting. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.
No description provided.