-
Notifications
You must be signed in to change notification settings - Fork 2
WIP on agent-generated ctime specs #46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
pgiarrusso-sl
wants to merge
17
commits into
main
Choose a base branch
from
paolo/agent-ctime
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
7593257
First attempt at agent-generated ctime specs
pgiarrusso-sl 732bd10
Delete debugging nonsense from specs
pgiarrusso-sl 4f3e7eb
Iterate on specs
pgiarrusso-sl 16cbfca
One more pass
pgiarrusso-sl 1633ab8
More proof repairs
pgiarrusso-sl d44541c
Manual proof repair
pgiarrusso-sl 52521f6
Automated proof repair for new prelude
pgiarrusso-sl d14c16e
Fix bug reports
pgiarrusso-sl 06f90a7
Add tmR_learnable, fix mktime spec and clients
pgiarrusso-sl f73b6ff
Some more proof repair
pgiarrusso-sl 1b22996
Next attempt
pgiarrusso-sl 0bfdab9
Agent-generated edits (weakens lemmas)
pgiarrusso-sl 862bc06
Revise helper lemmas by hand (strengthens lemmas again)
pgiarrusso-sl ce49386
More agent work on tmR/tmR_hidden
pgiarrusso-sl 65332e8
More edits
pgiarrusso-sl 98ef5fc
Questionable edits
pgiarrusso-sl d4abf5a
WIP outputs (valuable?)
pgiarrusso-sl File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # ctime-repair | ||
|
|
||
| - Active proof target: `rocq-brick-libstdcpp/test/ctime/proof.v` | ||
| - Current reproduced failure from `dune build ./test/ctime/proof.vo`: | ||
| - non-fatal missing-spec diagnostics for POD repro lemmas via `verify?` | ||
| - earlier fatal proof failure at `test_mktime_ptr_ok` | ||
| - Live replay in `dune rocq top test/ctime/proof.v` found the wrapper-spec issue: | ||
| - using `\pre{q tm_in}` was still too strong and left a half-fraction ownership mismatch | ||
| - the correct wrapper statement uses `\prepost{q tm_in} tm_p |-> tmR q tm_in` | ||
| and makes the explicit post ask only for the pure `mktime_result` witness plus | ||
| `tm_p |-> tmR (cQp.scale (1 / 2) q) tm_out` | ||
| - under that statement, `verify_spec; go.` leaves only | ||
| `∃ t0 : time_t_model, [| mktime_result tm_in t t0 |]` | ||
| - `iExists _. go.` closes the proof | ||
| - Current repair choice: | ||
| - keep the `test_mktime_ptr_ok` proof as | ||
| `verify_spec. go. iExists _. go. Qed.` |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| - Restoring stack-local tm/timespec validation clients to reproduce synthetic destructor proof failures. |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # `<ctime>` BRiCk Spec Design | ||
|
|
||
| ## 1. Summary | ||
|
|
||
| 1. Add a new `proof/ctime` folder and a companion `test/ctime` folder. | ||
| 2. Cover the standard `<ctime>` surface from cppreference and C11 7.27, with `difftime` deferred because BRiCk does not currently support doubles. | ||
| 3. Use an abstract-but-accurate design: explicit ownership for writable outputs, borrowed resources for static return objects, and abstract model relations for time conversion and formatting. | ||
|
|
||
| ## 2. Public API and Representation Changes | ||
|
|
||
| 1. The proof folder contains `inc_ctime.cpp`, `pred.v`, `model.v`, and `spec.v`. | ||
| 2. Specs target the unqualified names emitted by `cpp2v`: `clock`, `time`, `mktime`, `gmtime`, `localtime`, `asctime`, `ctime`, `strftime`, and `timespec_get`. | ||
| 3. V1 remains standard-only and excludes glibc and POSIX extensions visible in the generated AST. | ||
| 4. The model layer exports `tm_model` and `timespec_model`. | ||
| 5. `tmR` hides non-standard `tm_gmtoff` and `tm_zone` fields behind `tmR_hidden`, while `timespecR` tracks only `tv_sec` and `tv_nsec`. | ||
|
|
||
| ## 3. Specification Design | ||
|
|
||
| 1. `clock` and `time` are modeled as abstract current-time queries over signed integer results. | ||
| 2. `timespec_get` is only specified for `TIME_UTC = 1`. | ||
| 3. `mktime`, `gmtime`, and `localtime` use abstract conversion and normalization relations instead of a concrete calendar algorithm. | ||
| 4. `asctime` and `ctime` return borrowed C strings with explicit close obligations, matching the existing static-storage style used elsewhere in the repo. | ||
| 5. `strftime` writes into a caller-owned `cstring.bufR` buffer and returns either `0` or the produced string length. | ||
|
|
||
| ## 4. Validation Plan | ||
|
|
||
| 1. `test/ctime/test.cpp` exercises `std::time`, `std::timespec_get`, `std::mktime`, `std::gmtime`, `std::localtime`, `std::asctime`, `std::ctime`, `std::strftime`, and repeated static-return calls. | ||
| 2. `test/ctime/proof.v` proves representative client lemmas against the new specs. | ||
| 3. The test clients use `std::`-qualified calls so the proof confirms those names resolve against the unqualified spec entries produced by `cpp2v`. | ||
|
|
||
| ## 5. Known Deviation | ||
|
|
||
| 1. `difftime` is intentionally deferred until BRiCk has a supported story for `double` values in specs and proofs. |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| #include <ctime> |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| (* | ||
| * Copyright (c) 2025 SkyLabs AI, Inc. | ||
| * This software is distributed under the terms of the BedRock Open-Source License. | ||
| * See the LICENSE-BedRock file in the repository root for details. | ||
| *) | ||
| Require Import skylabs.auto.cpp.prelude.spec. | ||
| Require Export skylabs.cpp.string. | ||
|
|
||
| #[local] Set Primitive Projections. | ||
| #[local] Open Scope Z_scope. | ||
|
|
||
| Record tm_t := { | ||
| tm_model_sec : Z; | ||
| tm_model_min : Z; | ||
| tm_model_hour : Z; | ||
| tm_model_mday : Z; | ||
| tm_model_mon : Z; | ||
| tm_model_year : Z; | ||
| tm_model_wday : Z; | ||
| tm_model_yday : Z; | ||
| tm_model_isdst : Z; | ||
| }. | ||
|
|
||
| Record timespec_t := { | ||
| timespec_model_sec : Z; | ||
| timespec_model_nsec : Z; | ||
| }. | ||
|
|
||
| Definition TIME_UTC : Z := 1. | ||
|
|
||
| Definition clock_t := Z. | ||
| Definition time_t := Z. | ||
|
|
||
| Parameter abs_time_t : Type. | ||
| Parameter abs_time_of_N : N -> abs_time_t. | ||
| Parameter abs_time_diff_t : Type. | ||
|
|
||
| Definition timespec_wf (ts : timespec_t) : Prop := | ||
| 0 <= timespec_model_nsec ts < 1000000000. | ||
|
|
||
| Parameter time_t_to_abs_time : time_t -> abs_time_t -> Prop. | ||
| Parameter timespec_to_abs_time : timespec_t -> abs_time_t -> Prop. | ||
| Parameter clock_t_to_abs_time_diff : clock_t -> abs_time_diff_t -> Prop. | ||
| Parameter abs_time_plus_diff : abs_time_t -> abs_time_diff_t -> abs_time_t -> Prop. | ||
|
|
||
| Parameter utc_time_to_tm : time_t -> tm_t -> Prop. | ||
| Parameter local_time_to_tm : time_t -> tm_t -> Prop. | ||
| Parameter mktime_result : tm_t -> tm_t -> time_t -> Prop. | ||
| Parameter asctime_text_of : tm_t -> cstring.t -> Prop. | ||
| Parameter strftime_text_of : cstring.t -> tm_t -> cstring.t -> Prop. | ||
|
|
||
| Definition ctime_text_of (t : time_t) (out : cstring.t) : Prop := | ||
| exists tm, local_time_to_tm t tm /\ asctime_text_of tm out. | ||
|
|
||
| Axiom asctime_text_of_len : | ||
| forall tm out, | ||
| asctime_text_of tm out -> | ||
| cstring.size out = 25. | ||
|
|
||
| Axiom strftime_text_of_fit : | ||
| forall fmt tm out bound, | ||
| strftime_text_of fmt tm out -> | ||
| bound = cstring.size out -> | ||
| 0 <= bound. | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| # `<ctime>` Refactor And Proof-Repair Plan | ||
|
|
||
| ## Summary | ||
|
|
||
| 1. Keep both client styles in `test/ctime`: green wrapper clients for normal validation and stack-local POD repro clients for the `tm::~tm()` / `timespec::~timespec()` verifier completeness bug. | ||
| 2. Refactor the `ctime` proof stack so `model.v` is pure-only and `pred.v` owns all separation predicates, including `later_than`, `tmR`, and `timespecR`. | ||
| 3. Rework `tmR` with `sl.lock` and `#[only(lazy_unfold)] derive` so it stays abstract in client proofs while hiding non-standard `tm` fields. | ||
| 4. Repair as many non-repro proofs as possible, using `dune coq top` / `dune rocq top` for live replay, while keeping the POD repro lemmas explicit and buildable. | ||
|
|
||
| ## Key Changes | ||
|
|
||
| 1. Refactor the layer split. | ||
| `model.v` will contain only pure definitions and `Prop`-valued relations. | ||
| Move `tm_model` and `timespec_model` into `model.v`. | ||
| Keep `TIME_UTC`, `clock_t_model`, `time_t_model`, `clock_result`, `timespec_get_result`, `utc_time_to_tm`, `local_time_to_tm`, `mktime_result`, `asctime_text_of`, `strftime_text_of`, and `ctime_text_of` in `model.v`. | ||
| `pred.v` will import `model.v` and define all `Rep` / `mpred`-valued abstractions. | ||
|
|
||
| 2. Replace `current_time_result` with `later_than` in `pred.v`. | ||
| Remove `current_time_result` entirely. | ||
| Define `later_than` as a `Parameter`, not by copy-pasting the class-based NOVA code. | ||
| Add the needed supporting declarations in parameter/axiom form: `Knowledge1 later_than`, `Timeless1 later_than`, `WeaklyObjective1 later_than`, and the down-closed law. | ||
| Do not add `Hint Opaque later_than` or `Arguments later_than : simpl never.`, since `later_than` is a parameter and those lines would add no value. | ||
| Update the `time` spec so success returns the integer time value and `later_than` for that value, and `time(&t)` also writes the same integer to `*t`. | ||
|
|
||
| 3. Rework `tmR` to match the intended public contract. | ||
| Publicly expose only the 9 ISO C `tm` fields via `tm_model`. | ||
| Keep `tm_gmtoff` and `tm_zone` hidden inside `tmR_hidden`. | ||
| Do not decide now whether `tm_zone` is owned, borrowed, or ignored; hide that choice inside `tmR_hidden` and add a TODO comment for later investigation. | ||
| Implement the exported `tmR` through a locked wrapper. | ||
| Prefer `sl.lock` and `#[only(lazy_unfold)] derive` to solve the current transparency issue instead of ad hoc opacity hints. | ||
| Apply the same style to any other exported rep that needs abstraction control in client proofs. | ||
|
|
||
| 4. Keep `timespecR` simple and standard-facing. | ||
| `timespecR` continues to describe only `tv_sec` and `tv_nsec`. | ||
| If abstraction control is needed for `timespecR`, use the same locked/lazy-unfold pattern as `tmR`. | ||
|
|
||
| 5. Update the client suite to include both green and repro paths. | ||
| Add pointer-wrapper clients for `timespec_get` and `mktime` so those APIs have green proof-backed coverage without local POD cleanup. | ||
| Keep stack-local POD repro clients for both `std::timespec` and `std::tm`. | ||
| Keep direct green clients for `gmtime`, `localtime`, `asctime`, `ctime`, `strftime`, and repeated static-return calls, unless proof replay shows a strictly better shape. | ||
| Keep `main()` on the green path only so `main_ok` remains part of the normal successful build. | ||
|
|
||
| 6. Update `test/ctime/proof.v` to reflect the split. | ||
| Fully prove the green clients where feasible. | ||
| Keep the POD repro lemmas under `verify?` and explicitly `Admitted` if the destructor-spec bug still blocks them. | ||
| Add short comments stating that those lemmas intentionally preserve a verifier completeness repro. | ||
| For non-repro lemmas, do not stop at the first failure: try to repair each proof, or leave the most-progress script if full discharge is still blocked. | ||
|
|
||
| ## Proof Repair Strategy | ||
|
|
||
| 1. First fix the representation-level blocker. | ||
| Refactor `tmR` and `timespecR` so client proofs no longer fail on transparent rep expansion. | ||
|
|
||
| 2. Then replay each non-repro client proof individually. | ||
| Use `dune coq top` or `dune rocq top` from the `rocq-brick-libstdcpp` project root as the default live environment. | ||
| Prefer dune-managed tops over plain `coqtop` for proof inspection and debugging. | ||
| Keep proof edits local and minimal; do not introduce broad infrastructure unless repeated failures show it is necessary. | ||
|
|
||
| 3. Treat the POD destructor repros separately. | ||
| Preserve isolated repro lemmas for local `tm` and local `timespec`. | ||
| Keep them buildable through explicit admissions if the verifier still insists on destructor specs without bodies. | ||
|
|
||
| ## Validation Plan | ||
|
|
||
| 1. Rebuild `./test/ctime/proof.vo` as the main acceptance target. | ||
| 2. Confirm the green path proves successfully, including `main()`. | ||
| 3. Confirm the POD repro lemmas remain present and documented. | ||
| 4. Confirm the generated `test_cpp.v` still contains local `tm` and `timespec` objects for the repro cases. | ||
| 5. Re-run proof replay on every non-repro lemma and retain the strongest checked script reached for each one. | ||
|
|
||
| ## Assumptions And Defaults | ||
|
|
||
| 1. The final `ctime` test theory should stay buildable even if POD repro lemmas remain admitted. | ||
| 2. `later_than` is a local `ctime` abstraction in `pred.v`, not an import of NOVA’s shared predicate framework. | ||
| 3. The `tm_zone` ownership question is intentionally deferred and hidden inside `tmR_hidden`. | ||
| 4. `difftime` remains deferred. |
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
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,109 @@ | ||||||
| (* | ||||||
| * Copyright (c) 2025 SkyLabs AI, Inc. | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| * This software is distributed under the terms of the BedRock Open-Source License. | ||||||
| * See the LICENSE-BedRock file in the repository root for details. | ||||||
| *) | ||||||
| Require Import skylabs.auto.cpp.prelude.proof. | ||||||
| Require Import skylabs.auto.cpp.elpi.derive. | ||||||
| Require Export skylabs.cpp.string. | ||||||
| Require Export skylabs.brick.libstdcpp.iostream.pred. | ||||||
|
|
||||||
| Require Export skylabs.brick.libstdcpp.ctime.model. | ||||||
| Require Import skylabs.brick.libstdcpp.ctime.inc_ctime_cpp. | ||||||
|
|
||||||
| #[local] Set Primitive Projections. | ||||||
|
|
||||||
| Section with_cpp. | ||||||
| Context `{Σ : cpp_logic, σ : genv}. | ||||||
|
|
||||||
| Parameter later_than : abs_time_t -> mpred. | ||||||
| #[global] Declare Instance later_than_knowledge : Knowledge1 later_than. | ||||||
| #[global] Declare Instance later_than_timeless : Timeless1 later_than. | ||||||
| #[global] Declare Instance later_than_weakly_objective : WeaklyObjective1 later_than. | ||||||
| Axiom later_than_down_closed : | ||||||
| forall t1 t2, | ||||||
| (t1 <= t2)%N -> | ||||||
| later_than (abs_time_of_N t2) |-- later_than (abs_time_of_N t1). | ||||||
|
|
||||||
| Parameter system_start_at : abs_time_t -> mpred. | ||||||
| #[global] Declare Instance system_start_at_knowledge : Knowledge1 system_start_at. | ||||||
| #[global] Declare Instance system_start_at_timeless : Timeless1 system_start_at. | ||||||
| #[global] Declare Instance system_start_at_weakly_objective : WeaklyObjective1 system_start_at. | ||||||
|
|
||||||
| (** Correctness of a [time] result, relative to the current-time world. *) | ||||||
| Definition time_result (t : time_t) : mpred := | ||||||
| [| 0 <= t |] ** | ||||||
| Exists now, | ||||||
| [| time_t_to_abs_time t now |] ** | ||||||
| later_than now. | ||||||
| #[global] Hint Opaque time_result : typeclass_instances sl_opacity. | ||||||
| #[global] Arguments time_result : simpl never. | ||||||
|
|
||||||
| (** Correctness of a [timespec_get] result, relative to current absolute time. *) | ||||||
| Definition timespec_get_result (ts : timespec_t) : mpred := | ||||||
| [| timespec_wf ts |] ** | ||||||
| Exists now, | ||||||
| [| timespec_to_abs_time ts now |] ** | ||||||
| later_than now. | ||||||
| #[global] Hint Opaque timespec_get_result : typeclass_instances sl_opacity. | ||||||
| #[global] Arguments timespec_get_result : simpl never. | ||||||
|
|
||||||
| (** Correctness of a [clock] result as duration since system start. *) | ||||||
| Definition clock_result (ticks : clock_t) : mpred := | ||||||
| [| 0 <= ticks |] ** | ||||||
| Exists diff start now, | ||||||
| [| clock_t_to_abs_time_diff ticks diff |] ** | ||||||
| system_start_at start ** | ||||||
| [| abs_time_plus_diff start diff now |] ** | ||||||
| later_than now. | ||||||
| #[global] Hint Opaque clock_result : typeclass_instances sl_opacity. | ||||||
| #[global] Arguments clock_result : simpl never. | ||||||
|
|
||||||
| (** Representation of the hidden, non-standard tail of [struct tm]. | ||||||
|
|
||||||
| This predicate is the only place where the glibc-specific fields | ||||||
| [tm_gmtoff] and [tm_zone] may appear. It is meant to describe those | ||||||
| fields relative to the enclosing [tm] object while keeping their exact | ||||||
| ownership story abstract from clients of [tmR]. | ||||||
|
|
||||||
| This predicate is intentionally unindexed: a provisional equation for a | ||||||
| dummy hidden model would become part of the interface and make later | ||||||
| refinements breaking changes. If clients eventually need semantic facts | ||||||
| about the non-standard tail, introduce that model deliberately then. | ||||||
|
|
||||||
| TODO: investigate whether [tm_zone] should be owned, borrowed, or | ||||||
| abstracted away by this hidden representation. *) | ||||||
| Parameter tmR_hidden : cQp.t -> Rep. | ||||||
| #[only(cfracsplittable)] derive tmR_hidden. | ||||||
|
|
||||||
| Parameter timespecR_raw : cQp.t -> timespec_t -> Rep. | ||||||
| #[only(type_ptr="timespec", cfracsplittable)] derive timespecR_raw. | ||||||
| End with_cpp. | ||||||
|
|
||||||
| sl.lock | ||||||
| Definition tmR `{Σ : cpp_logic} {σ : genv} (q : cQp.t) (tm : tm_t) : Rep := | ||||||
| structR "tm" q ** | ||||||
| _field "tm::tm_sec" |-> primR Tint q (Vint tm.(tm_model_sec)) ** | ||||||
| _field "tm::tm_min" |-> primR Tint q (Vint tm.(tm_model_min)) ** | ||||||
| _field "tm::tm_hour" |-> primR Tint q (Vint tm.(tm_model_hour)) ** | ||||||
| _field "tm::tm_mday" |-> primR Tint q (Vint tm.(tm_model_mday)) ** | ||||||
| _field "tm::tm_mon" |-> primR Tint q (Vint tm.(tm_model_mon)) ** | ||||||
| _field "tm::tm_year" |-> primR Tint q (Vint tm.(tm_model_year)) ** | ||||||
| _field "tm::tm_wday" |-> primR Tint q (Vint tm.(tm_model_wday)) ** | ||||||
| _field "tm::tm_yday" |-> primR Tint q (Vint tm.(tm_model_yday)) ** | ||||||
| _field "tm::tm_isdst" |-> primR Tint q (Vint tm.(tm_model_isdst)) ** | ||||||
| tmR_hidden q. | ||||||
| #[only(lazy_unfold)] derive tmR. | ||||||
| #[only(type_ptr,cfracsplittable)] derive tmR. | ||||||
|
|
||||||
| sl.lock | ||||||
| Definition timespecR `{Σ : cpp_logic} {σ : genv} (q : cQp.t) (ts : timespec_t) : Rep := | ||||||
| timespecR_raw q ts. | ||||||
| #[only(lazy_unfold)] derive timespecR. | ||||||
| #[only(type_ptr,cfracsplittable)] derive timespecR. | ||||||
|
|
||||||
| #[global] Instance tmR_learnable `{Σ : cpp_logic} {σ : genv} : LearnEqF1 tmR := | ||||||
| ltac:(solve_learnable). | ||||||
|
|
||||||
| #[global] Instance timespecR_learnable `{Σ : cpp_logic} {σ : genv} : LearnEqF1 timespecR := | ||||||
| ltac:(solve_learnable). | ||||||
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.