Skip to content

feat(integration-tests): Add package search testing verification infra.#2235

Open
quinntaylormitchell wants to merge 31 commits into
y-scope:mainfrom
quinntaylormitchell:testing-redesign-9
Open

feat(integration-tests): Add package search testing verification infra.#2235
quinntaylormitchell wants to merge 31 commits into
y-scope:mainfrom
quinntaylormitchell:testing-redesign-9

Conversation

@quinntaylormitchell

@quinntaylormitchell quinntaylormitchell commented Apr 29, 2026

Copy link
Copy Markdown
Collaborator

Description

This PR adds the action and verification infrastructure for testing package search.

Checklist

  • The PR satisfies the contribution guidelines.
  • This is a breaking change and that has been indicated in the PR title, OR this isn't a
    breaking change.
  • Necessary docs have been updated, OR no docs need to be updated.

Validation performed

Tested on development branch; all tests pass.

Summary by CodeRabbit

  • Tests
    • Added a package search test utility supporting multiple modes (file-targeting, case-insensitive, counts, count-by-time, time-range).
    • Added structured/typed search arguments for clearer test intents and commands.
    • Verification now compares search results against a reference tool and reports detailed pass/fail on mismatches.
    • Test dataset metadata now includes explicit single-file match entries to stabilize single-match scenarios.

@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a typed SearchArgs builder, ClpPackageSearchType modes, functions to construct and run CLP package search actions, grep-based verification helpers that normalize results per mode, and a new dataset metadata field plus validation for a single-match file.

Changes

Search Test Utilities

Layer / File(s) Summary
Module header and SearchArgs builder
integration-tests/tests/package_tests/utils/search.py
Module imports, logger, default interval constant, and SearchArgs with to_cmd() building CLI flags for dataset/file targeting, ignore-case, count modes, time bounds, raw output, and wildcard query.
Search modes and action construction
integration-tests/tests/package_tests/utils/search.py
ClpPackageSearchType enum plus search_clp_package() and _construct_args() mapping dataset metadata to CLI flags and returning a ClpAction with typed SearchArgs.
Verification flow and helpers
integration-tests/tests/package_tests/utils/search.py
verify_search_action() validates exit code and SearchArgs, builds a mode-specific grep command, runs grep, and compares normalized grep output to normalized CLP output. Helper functions: _construct_grep_verification_cmd(), _get_grep_options_from_search_type(), _format_grep_result_for_search_type(), _format_search_result_for_search_type().

Dataset Metadata

Layer / File(s) Summary
single_match_file metadata and validation
integration-tests/tests/utils/classes.py, integration-tests/tests/data/json_multifile/metadata.json, integration-tests/tests/data/text_multifile/metadata.json
Adds single_match_file field to SampleDatasetMetadata and a SampleDataset.__post_init__ check that raises ValueError if the specified file is not present in metadata.file_names. Corresponding dataset metadata files include the new field.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Test Code
    participant Builder as SearchArgs / search_clp_package
    participant CLP as CLP subprocess
    participant Verifier as verify_search_action
    participant Grep as grep subprocess

    Test->>Builder: request ClpAction(dataset, type, query)
    Builder-->>Test: ClpAction (cmd list, SearchArgs)
    Test->>CLP: run ClpAction subprocess
    CLP-->>Test: exit code + stdout
    Test->>Verifier: verify_search_action(action, type, dataset)
    Verifier->>Verifier: check exit code & args
    Verifier->>Grep: run mode-specific grep on dataset logs or file path
    Grep-->>Verifier: grep stdout / exit code
    Verifier->>Verifier: normalize outputs and compare
    Verifier-->>Test: VerificationResult.ok() or fail(message)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • y-scope/clp#2231: Related infrastructure for typed action/verification plumbing used by the new search/verification helpers.

Suggested reviewers

  • junhaoliao
  • Bill-hbrhbr
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding package search testing and verification infrastructure.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@quinntaylormitchell quinntaylormitchell changed the title feat(integration-tests): Add search infra. feat(integration-tests): Add search action and verification infra. Apr 29, 2026
@quinntaylormitchell quinntaylormitchell marked this pull request as ready for review April 29, 2026 23:41
@quinntaylormitchell quinntaylormitchell requested a review from a team as a code owner April 29, 2026 23:41

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@integration-tests/tests/package_tests/utils/search.py`:
- Line 134: When running in FILE_PATH mode, guard against empty metadata
file_names before indexing: check that dataset.metadata.file_names is non-empty
(e.g., len(dataset.metadata.file_names) > 0 or truthiness) before using
dataset.metadata.file_names[0]; if empty, raise a clear assertion or ValueError
with a useful message rather than letting IndexError bubble up. Update the
assignment to args.file_path to only occur after this guard; reference the
existing identifiers args.file_path, dataset.metadata.file_names, and FILE_PATH
mode to locate and modify the code.
- Around line 176-177: Replace the bare assert on "args = action.args" with
explicit error handling: check "isinstance(args, SearchArgs)" and if false
return a VerificationResult.fail(...) with a clear message (matching other
validations in this function). Use the same VerificationResult type used
elsewhere in this file so invalid action.args is handled consistently rather
than being stripped by Python -O; reference the variables "args" and
"action.args" and the classes "SearchArgs" and "VerificationResult".
- Around line 184-188: The check treating any non-zero grep exit code as failure
is too strict: GNU grep returns 1 when no matches are found. Update the
condition in the block that inspects grep_action.completed_proc.returncode to
only fail when the return code is neither 0 nor 1 (i.e., allow 0 and 1), and
keep the pytest.fail call that references grep_action.log_file_path for true
errors; ensure you still reference grep_action.completed_proc.returncode and
pytest.fail in the same location.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ef0fc03e-e41f-4ba2-b226-b05ab2ce3723

📥 Commits

Reviewing files that changed from the base of the PR and between 298e2e2 and 3b62e1f.

📒 Files selected for processing (2)
  • integration-tests/tests/package_tests/utils/search.py
  • integration-tests/tests/utils/classes.py

Comment thread integration-tests/tests/package_tests/utils/search.py Outdated
Comment thread integration-tests/tests/package_tests/utils/search.py Outdated
Comment thread integration-tests/tests/package_tests/utils/search.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@integration-tests/tests/package_tests/utils/search.py`:
- Around line 282-286: The COUNT_BY_TIME branch currently uses re.search which
only returns the first "count: <n>" match; change the logic in the case handling
for ClpPackageSearchType.COUNT_RESULTS | ClpPackageSearchType.COUNT_BY_TIME to
use re.findall(r"count: (\d+)", search_result) (or an iterator like re.finditer)
to collect all count buckets, return them joined with "\n" and a trailing
newline, and call pytest.fail if the resulting list is empty; keep the same
match formatting and error message behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 22395b96-f587-4100-b7c2-fa030589ad7f

📥 Commits

Reviewing files that changed from the base of the PR and between 3b62e1f and f9d3189.

📒 Files selected for processing (1)
  • integration-tests/tests/package_tests/utils/search.py

Comment thread integration-tests/tests/package_tests/utils/search.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
integration-tests/tests/package_tests/utils/search.py (2)

175-176: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace assert with explicit verification failure handling.

assert can be stripped with Python optimization flags, which can bypass this validation path. Use explicit runtime handling and return a typed verification failure instead.

Suggested fix
     args = action.args
-    assert isinstance(args, SearchArgs)
+    if not isinstance(args, SearchArgs):
+        return action.fail_verification(
+            "Search verification requires `action.args` to be a SearchArgs instance."
+        )
In Python, are assert statements removed when running with optimization flags like -O?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integration-tests/tests/package_tests/utils/search.py` around lines 175 -
176, The code uses an assert to check the type of action.args which can be
bypassed with Python -O; replace the assert with an explicit runtime check on
action.args (e.g., inspect isinstance(action.args, SearchArgs)) and on failure
raise or return the appropriate verification failure value used by this test
harness (do not rely on AssertionError). Update the handling around
args/action.args and SearchArgs so the function returns or raises the typed
verification failure the test framework expects instead of using assert.

269-273: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

COUNT_BY_TIME parsing only reads the first bucket.

re.search only captures one count: value, so multi-bucket count-by-time output is verified incorrectly. Aggregate all buckets before comparing.

Suggested fix
         case ClpPackageSearchType.COUNT_RESULTS | ClpPackageSearchType.COUNT_BY_TIME:
-            match = re.search(r"count: (\d+)", search_result)
-            if match:
-                return match.group(1) + "\n"
+            counts = [int(value) for value in re.findall(r"count:\s*(\d+)", search_result)]
+            if counts:
+                return f"{sum(counts)}\n"
             pytest.fail(f"The search result '{search_result}' wasn't in the correct format.")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integration-tests/tests/package_tests/utils/search.py` around lines 269 -
273, The COUNT_BY_TIME branch currently uses re.search which only captures the
first "count: X" and misses additional buckets; update the block handling
ClpPackageSearchType.COUNT_RESULTS | ClpPackageSearchType.COUNT_BY_TIME to use
re.findall(r"count: (\d+)", search_result), convert all matches to integers, sum
them (or otherwise aggregate all bucket counts as required), and return the
aggregated value as a string with a trailing newline (e.g., str(total) + "\n");
keep the pytest.fail call if no matches are found.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@integration-tests/tests/package_tests/utils/search.py`:
- Around line 175-176: The code uses an assert to check the type of action.args
which can be bypassed with Python -O; replace the assert with an explicit
runtime check on action.args (e.g., inspect isinstance(action.args, SearchArgs))
and on failure raise or return the appropriate verification failure value used
by this test harness (do not rely on AssertionError). Update the handling around
args/action.args and SearchArgs so the function returns or raises the typed
verification failure the test framework expects instead of using assert.
- Around line 269-273: The COUNT_BY_TIME branch currently uses re.search which
only captures the first "count: X" and misses additional buckets; update the
block handling ClpPackageSearchType.COUNT_RESULTS |
ClpPackageSearchType.COUNT_BY_TIME to use re.findall(r"count: (\d+)",
search_result), convert all matches to integers, sum them (or otherwise
aggregate all bucket counts as required), and return the aggregated value as a
string with a trailing newline (e.g., str(total) + "\n"); keep the pytest.fail
call if no matches are found.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 07eaf020-0cb0-448f-80b7-6cc6a26a3283

📥 Commits

Reviewing files that changed from the base of the PR and between 89677f8 and 613925f.

📒 Files selected for processing (2)
  • integration-tests/tests/package_tests/utils/search.py
  • integration-tests/tests/utils/classes.py

@Bill-hbrhbr Bill-hbrhbr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR doesn't actually include any search tests right? Let's include them instead of simply introducing a portion of the search test infra.
Also, most of my concerns are elaborated in the comments.

Comment thread integration-tests/tests/package_tests/utils/search.py Outdated
Comment thread integration-tests/tests/package_tests/utils/search.py Outdated
Comment thread integration-tests/tests/package_tests/utils/search.py Outdated
Comment thread integration-tests/tests/data/json_multifile/metadata.json Outdated
Comment thread integration-tests/tests/package_tests/utils/search.py Outdated
Comment thread integration-tests/tests/utils/classes.py Outdated
@quinntaylormitchell quinntaylormitchell changed the title feat(integration-tests): Add search action and verification infra. feat(integration-tests): Add clp-json search verification infra. Jul 5, 2026
@quinntaylormitchell quinntaylormitchell changed the title feat(integration-tests): Add clp-json search verification infra. feat(integration-tests): Add search action and verification infra. Jul 5, 2026
@quinntaylormitchell quinntaylormitchell changed the title feat(integration-tests): Add search action and verification infra. feat(integration-tests): Add package search testing verification infra. Jul 5, 2026
class EpochMsTimestampFormat(BaseModel):
"""Indicates a timestamp encoded as an integer number of milliseconds since the UNIX epoch."""

kind: Literal["epoch_ms"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
kind: Literal["epoch_ms"]
type: Literal["epoch"]
unit: Literal["s", "ms", "us", "ns"]

I like the type key name better than the kind. Sounds more canonical.
Also I think it be beneficial to have epoch as a category and ms in a separate unit key.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the type key name better than the kind.

Agreed; changed to type

I think it be beneficial to have epoch as a category and ms in a separate unit key

I think I’m going to leave it as epoch_ms for now, but later if/when we add datasets with other units, I’m happy to update it.

@@ -0,0 +1,350 @@
"""Search verification helpers specific to the clp-json package."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since there are no actual new additions of clp-json tests, can we defer this to the PR where we add the actual tests?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why the tests from test_clp_json.py were removed, since that file seems to contain a fairly comprehensive set of utilities for validating clp-json query results. My two comments:

  1. The JSON parsing utilities would probably be better placed in the general utilities folder so they can be reused by other tests.
  2. As a starting point, I think we could simply verify the total match count when testing clp-json search results. That would let us add basic coverage without having to deal with parsing JSON strings right away.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we defer this to the PR where we add the actual tests

Will discuss offline

I'm not sure why the tests from test_clp_json.py were removed

Not sure what you are referring to; other than the removal of the placeholder test (which I have now restored) this PR doesn't remove any utilities for validating clp-json query results; it adds them

The JSON parsing utilities would probably be better placed in the general utilities folder so they can be reused by other tests.

There are a lot of specialized methods that use (or are related to) JSON in this module, but other than moving strip_surrounding_quotes to the general utilities folder (which I have done) I don't see a lot of opportunity for reuse here. We can move any method(s) we choose at a later date if there ends up being concrete opportunity for reuse later on.

I think we could simply verify the total match count when testing clp-json search results.

Will discuss offline

logger.info("Verifying the compression of the 'text_multifile' dataset.")
result = verify_compress_unstructured_clp_json(action, clp_package, text_multifile)
assert result, result.failure_message

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto. let's not touch this part until we decide to include clp-json search tests.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

logger = logging.getLogger(__name__)


DEFAULT_COUNT_BY_TIME_INTERVAL = 10

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is currently not referenced anywhere. probably belonged to a removed clp-json search test.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right on, thank you

DEFAULT_COUNT_BY_TIME_INTERVAL = 10


def parse_timestamp_to_epoch_ms(timestamp: str, strptime_pattern: str) -> int:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should ideally be a function of class StrptimeTimestampFormat(BaseModel):

can be renamed to something like to_epoch_ms(timestamp: str).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve combined the two classes into a single class TimestampFormat and added a method called to_epoch_ms that handles the format conversion. If that’s not aligned with what you meant, let me know.

return [self.test_data_dir]


class EpochMsTimestampFormat(BaseModel):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, I think these new classes would be better placed in a dedicated timestamps.py module under the same utils directory. The current classes.py seems to be accumulating too many unrelated classes, so separating the timestamp-related ones into their own module would keep things better organized.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I’ve added it to a new file integration-tests/tests/utils/timestamps.py.

return filtered_entries


def _resolve_timestamp_to_ms(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be an API that's provided respectively by EpochMsTimestampFormat and StrptimeTimestampFormat. You can check if the format string is convertible for strptime and whether the value is integer for epoch timestamp.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If CLP is strictly taking epoch ms timestamps, EpochMsTimestampFormat and StrptimeTimestampFormat can share a base TimestampFormat class that provides the to_epoch_ms virtual method. Then TimestampFormat can represent more than a mere type alias.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve combined the two classes into a single class TimestampFormat and added a method called to_epoch_ms that handles the format conversion. If that’s not aligned with what you meant, let me know.

Comment on lines +109 to +116
"""
Constructs a key-value pair from a query string. The query is split on the first
`KV_DELIMITER_COLON` that is not inside a quoted group (`"..."` or `'...'`).

:param query:
:return: `(KEY, VALUE)` if `KV_DELIMITER_COLON` is present, else
`(WILDCARD_MULTIMATCH_CHAR, VALUE)`.
"""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using a constant KV_DELIMITER_COLON inside the docstring makes it a bit harder to read.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to align with the fact that KV_DELIMITER_COLON is what we use in the function; see comment below about changing to KV_DELIMITER; that might make it more readable.

Comment on lines +137 to +139
elif char in ('"', "'"):
open_quote = char
elif char == KV_DELIMITER_COLON:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why we use the KV_DELIMITER_COLON constant in one if statement but raw quote characters in another. For simple characters that are unlikely to change, I'd just use the literal characters consistently in both the code and the docstrings.
BTW, that's already the approach taken for the quote characters in _strip_surrounding_quotes's docstring.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main reason is that a delimiter can be anything (hypothetically), but the term "quotation marks" refers to a specific set of characters (either " or '). To me, it seems like delimiter characters are much more likely to change than quotation marks.

That being said, I'll rename KV_DELIMITER_COLON to KV_DELIMITER to fully recognize that it may change.

Also: not sure what you mean re. the docstrings; fairly sure that all methods in this file refer to quotation marks as literals and to the delimiter character as KV_DELIMITER_COLON. Did I misunderstand you?

@@ -0,0 +1,179 @@
"""Search verification helpers specific to the clp-text package."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just realized that we don't have actual running search tests for clp-text either. I think it'd be beneficial to add count tests to verify that things are working.
Grep uses regex queries, while clp-text uses wildcard substring queries, so maybe we need regex and wildcard translation utilities? I know there is one inside clp_json/verification/search.py, so it's crucial that we put these general utilities under the general utils directory.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be beneficial to add count tests to verify that things are working.

Will discuss offline

maybe we need regex and wildcard translation utilities?

This module already has these utilities; did I misunderstand you?

it's crucial that we put these general utilities under the general utils directory.

Like the methods used in integration-tests/tests/package_tests/clp_text/verification/search.py, I don't see a lot of opportunity for reuse. For example, clp-json search verification does not use grep at all, and clp-text uses only grep.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants