Skip to content

feat(testing-system): add orthogonal decomposition evaluator MVP#107

Draft
MeteorsLiu wants to merge 7 commits intogoplus:mainfrom
MeteorsLiu:feat/matrix-reduce-mvp
Draft

feat(testing-system): add orthogonal decomposition evaluator MVP#107
MeteorsLiu wants to merge 7 commits intogoplus:mainfrom
MeteorsLiu:feat/matrix-reduce-mvp

Conversation

@MeteorsLiu
Copy link
Copy Markdown
Collaborator

No description provided.

@MeteorsLiu MeteorsLiu changed the title feat(testing-system): add orthogonal decomposition evaluator feat(testing-system): add orthogonal decomposition evaluator MVP Mar 15, 2026
@MeteorsLiu MeteorsLiu marked this pull request as draft March 15, 2026 15:45
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a robust testing framework that intelligently evaluates module build options. By tracing system calls during the build process, it constructs a detailed graph of actions and dependencies. This graph is then used to perform an orthogonal decomposition, identifying the minimal set of matrix combinations required for comprehensive testing, thereby significantly improving efficiency and reliability of module verification.

Highlights

  • New test Command and Orthogonal Decomposition Evaluator: Introduced a new test command to the llar tool, enabling automatic evaluation of matrix combinations for module testing. This system uses orthogonal decomposition to efficiently determine which build options are truly independent and which might collide, optimizing the number of test runs.
  • System Call Tracing Integration: Implemented a system call tracing mechanism (leveraging strace on Linux) to capture detailed build activities. This trace data is then analyzed to construct an action graph, classify build actions, and identify dependencies and outputs.
  • Enhanced Build System with OnTest Callback: The build system now supports an OnTest callback within module formulas, allowing for post-build verification steps. The buildModule function was refactored to buildModuleWithRunTest to accommodate this new testing phase.
  • Advanced Build Graph Analysis: Developed sophisticated logic for building and analyzing action graphs from trace records. This includes coalescing compile pipelines, classifying paths by their role (tooling, propagating, delivery, unknown), and identifying business-critical actions and control plane paths.
  • Debugging and Reporting Tools for Evaluator: Added a suite of debugging utilities and reporting mechanisms within the evaluator package. These tools provide detailed summaries of action graphs, diffs between build profiles, collision reports, and path facts, aiding in understanding and validating the evaluator's decisions.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • cmd/llar/internal/make.go
    • Added makeMatrix variable and a hidden --matrix flag for internal use to override matrix combinations.
    • Modified runMake to call buildModuleWithRunTest instead of buildModule.
  • cmd/llar/internal/test.go
    • Added a new test command to llar for building modules and executing onTest callbacks.
    • Introduced --verbose, --auto, and --trace-dump flags for the test command.
    • Implemented runTest and testModule functions for handling module testing logic, including automatic matrix evaluation.
  • cmd/llar/internal/test_trace_dump_test.go
    • Added unit tests for formatTraceDump function to ensure correct formatting of trace output.
  • formula/classfile.go
    • Added fOnTest field to ModuleF struct to store the onTest callback function.
    • Added OnTest method to ModuleF to set the fOnTest callback.
  • internal/build/build.go
    • Modified Builder struct to include runTest and trace boolean fields.
    • Updated Result struct to include Trace, TraceScope, TraceDiagnostics, and InputDigests fields.
    • Refactored buildModule into buildModuleWithRunTest to support onTest execution and trace capture.
    • Implemented logic to bypass build cache when runTest or trace is enabled.
    • Added collectTraceInputDigests, pathWithinRoot, and fileDigest helper functions for trace analysis.
  • internal/build/build_test.go
    • Added tests to verify that trace capture correctly targets only the main module and bypasses the build cache.
    • Included new test cases for NewBuilder and Build functionalities related to tracing.
  • internal/build/testdata/formulas/DaveGamble/cJSON/1.0.0/Cjson_llar.gox
    • Added new formula for DaveGamble/cJSON defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/DaveGamble/cJSON/versions.json
    • Added version metadata for DaveGamble/cJSON.
  • internal/build/testdata/formulas/PCRE2Project/pcre2/1.0.0/PCRE2_llar.gox
    • Added new formula for PCRE2Project/pcre2 defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/PCRE2Project/pcre2/versions.json
    • Added version metadata for PCRE2Project/pcre2.
  • internal/build/testdata/formulas/boostorg/boost/1.0.0/Boost_llar.gox
    • Added new formula for boostorg/boost defining its onBuild logic using shell commands.
  • internal/build/testdata/formulas/boostorg/boost/versions.json
    • Added version metadata for boostorg/boost.
  • internal/build/testdata/formulas/c-ares/c-ares/1.0.0/Cares_llar.gox
    • Added new formula for c-ares/c-ares defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/c-ares/c-ares/versions.json
    • Added version metadata for c-ares/c-ares.
  • internal/build/testdata/formulas/facebook/zstd/1.0.0/Zstd_llar.gox
    • Added new formula for facebook/zstd defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/facebook/zstd/versions.json
    • Added version metadata for facebook/zstd.
  • internal/build/testdata/formulas/fmtlib/fmt/1.0.0/Fmt_llar.gox
    • Added new formula for fmtlib/fmt defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/fmtlib/fmt/versions.json
    • Added version metadata for fmtlib/fmt.
  • internal/build/testdata/formulas/gabime/spdlog/1.0.0/Spdlog_llar.gox
    • Added new formula for gabime/spdlog defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/gabime/spdlog/versions.json
    • Added version metadata for gabime/spdlog.
  • internal/build/testdata/formulas/jbeder/yaml-cpp/1.0.0/Yamlcpp_llar.gox
    • Added new formula for jbeder/yaml-cpp defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/jbeder/yaml-cpp/versions.json
    • Added version metadata for jbeder/yaml-cpp.
  • internal/build/testdata/formulas/libexpat/libexpat/1.0.0/Expat_llar.gox
    • Added new formula for libexpat/libexpat defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/libexpat/libexpat/versions.json
    • Added version metadata for libexpat/libexpat.
  • internal/build/testdata/formulas/libjpeg-turbo/libjpeg-turbo/1.0.0/Libjpegturbo_llar.gox
    • Added new formula for libjpeg-turbo/libjpeg-turbo defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/libjpeg-turbo/libjpeg-turbo/versions.json
    • Added version metadata for libjpeg-turbo/libjpeg-turbo.
  • internal/build/testdata/formulas/libsdl-org/libtiff/1.0.0/Libtiff_llar.gox
    • Added new formula for libsdl-org/libtiff defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/libsdl-org/libtiff/versions.json
    • Added version metadata for libsdl-org/libtiff.
  • internal/build/testdata/formulas/pocoproject/poco/1.0.0/Poco_llar.gox
    • Added new formula for pocoproject/poco defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/pocoproject/poco/versions.json
    • Added version metadata for pocoproject/poco.
  • internal/build/testdata/formulas/sqlite/sqlite/1.0.0/Sqlite_llar.gox
    • Added new formula for sqlite/sqlite defining its onBuild logic using shell commands.
  • internal/build/testdata/formulas/sqlite/sqlite/versions.json
    • Added version metadata for sqlite/sqlite.
  • internal/build/testdata/formulas/test/tracecmake/1.0.0/Tracecmake_llar.gox
    • Added new formula for test/tracecmake defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/test/tracecmake/versions.json
    • Added version metadata for test/tracecmake.
  • internal/build/testdata/formulas/test/traceoptions/1.0.0/Traceoptions_llar.gox
    • Added new formula for test/traceoptions defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/test/traceoptions/versions.json
    • Added version metadata for test/traceoptions.
  • internal/build/testdata/formulas/uriparser/uriparser/1.0.0/Uriparser_llar.gox
    • Added new formula for uriparser/uriparser defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/uriparser/uriparser/versions.json
    • Added version metadata for uriparser/uriparser.
  • internal/build/testdata/formulas/webmproject/libwebp/1.0.0/Libwebp_llar.gox
    • Added new formula for webmproject/libwebp defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/webmproject/libwebp/versions.json
    • Added version metadata for webmproject/libwebp.
  • internal/build/testdata/formulas/zeux/pugixml/1.0.0/Pugixml_llar.gox
    • Added new formula for zeux/pugixml defining its onBuild logic using CMake.
  • internal/build/testdata/formulas/zeux/pugixml/versions.json
    • Added version metadata for zeux/pugixml.
  • internal/build/testdata/sources/test/tracecmake/CMakeLists.txt
    • Added CMakeLists.txt for test/tracecmake module, defining a static library and an executable.
  • internal/build/testdata/sources/test/tracecmake/cli.c
    • Added cli.c source file for the tracecli executable.
  • internal/build/testdata/sources/test/tracecmake/core.c
    • Added core.c source file for the tracecore library.
  • internal/build/testdata/sources/test/tracecmake/trace.h
    • Added trace.h header file for the tracecmake module.
  • internal/build/testdata/sources/test/tracecmake/trace_config.h.in
    • Added trace_config.h.in CMake configure file.
  • internal/build/testdata/sources/test/traceoptions/CMakeLists.txt
    • Added CMakeLists.txt for test/traceoptions module, defining conditional builds and installs.
  • internal/build/testdata/sources/test/traceoptions/cli.c
    • Added cli.c source file for the tracecli executable.
  • internal/build/testdata/sources/test/traceoptions/core.c
    • Added core.c source file for the tracecore library with conditional logic.
  • internal/build/testdata/sources/test/traceoptions/trace.h
    • Added trace.h header file for the traceoptions module.
  • internal/build/testdata/sources/test/traceoptions/trace_options.h.in
    • Added trace_options.h.in CMake configure file.
  • internal/evaluator/debug.go
    • Added debugging utilities for action graphs, including summary, diff, and collision reporting functions.
  • internal/evaluator/debug_test.go
    • Added tests for DebugSummary, DebugDiffSummary, and DebugCollisionSummary functions.
  • internal/evaluator/e2e_test.go
    • Added end-to-end tests for replaying trace dumps and generating graph summaries.
  • internal/evaluator/evaluator.go
    • Implemented the core Watch function for orthogonal decomposition evaluation, including action profiling and collision detection.
  • internal/evaluator/evaluator_test.go
    • Added extensive tests for the Watch function, covering various scenarios of independent and colliding options.
  • internal/evaluator/graph.go
    • Implemented action graph construction, action classification, compile pipeline merging, and path role assignment logic.
  • internal/evaluator/graph_test.go
    • Added comprehensive tests for action graph building, edge tracking, action classification, and compile pipeline merging.
  • internal/evaluator/replay_test.go
    • Added tests for replaying trace dumps and generating graph summaries for inspection.
  • internal/evaluator/report.go
    • Added DebugReport struct for aggregating and formatting debugging outputs from the evaluator.
  • internal/formula/formula.go
    • Updated Formula struct to include Matrix and OnTest fields for enhanced module definition.
    • Modified loadFS to correctly load the new Matrix and OnTest fields from classfiles.
  • internal/formula/formula_test.go
    • Updated TestLoadFS to verify the presence and invokability of the new OnTest callback.
  • internal/formula/testdata/formula/hello_llar.gox
    • Modified hello_llar.gox to include an onTest callback for demonstration purposes.
  • internal/trace/capture_linux.go
    • Added Linux-specific implementation for CaptureLockedThread using strace to capture system calls.
  • internal/trace/capture_unsupported.go
    • Added a build tag for unsupported operating systems for trace capture.
  • internal/trace/trace.go
    • Implemented core tracing functionality, including Record struct, ParseDiagnostics, CaptureResult, and Scope.
    • Added Watch function for build-only execution tracing and parseStraceRecordsDetailed for parsing strace output.
  • internal/trace/trace_test.go
    • Added tests for parsing strace records, including handling of failed syscalls, unfinished calls, and path resolution.
Activity
  • The pull request introduces a new test command to the llar tool, enabling a new workflow for module testing.
  • It integrates system call tracing capabilities, specifically using strace on Linux, to gather detailed execution data during builds.
  • The core build system has been extended to support onTest callbacks, allowing module authors to define post-build verification steps.
  • A new evaluator package has been added, containing the logic for orthogonal decomposition, action graph construction, and intelligent test matrix reduction.
  • Numerous test data files (formulas and source code) have been added to thoroughly test the new evaluator and tracing functionalities.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a significant new feature: a test command with an orthogonal decomposition evaluator to determine which matrix combinations require testing. This is a substantial piece of work involving build tracing, graph analysis, and complex heuristics. The overall approach is sophisticated and the implementation of the core evaluation logic is impressive. I've identified a few areas for improvement, mainly concerning code structure and maintainability, such as avoiding global state modifications between commands and reducing code duplication.

Comment thread cmd/llar/internal/test.go
Comment on lines +116 to +120
savedVerbose, savedOutput := makeVerbose, makeOutput
makeVerbose, makeOutput = testVerbose, ""
defer func() {
makeVerbose, makeOutput = savedVerbose, savedOutput
}()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The testModule function modifies global variables (makeVerbose, makeOutput) defined in make.go. This creates a tight, implicit coupling between the test and make commands, which can make the code harder to reason about, debug, and maintain. It's better to refactor the shared functionality, like buildModuleWithRunTest, to accept all its dependencies as explicit parameters instead of relying on global state.

Comment thread cmd/llar/internal/make.go
Comment on lines +76 to +82
matrix := formula.Matrix{
Require: map[string][]string{
"os": {runtime.GOOS},
"arch": {runtime.GOARCH},
},
}
matrixStr = matrix.Combinations()[0]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This logic for creating a default matrix from the current runtime OS and architecture is duplicated in cmd/llar/internal/test.go. To improve maintainability and avoid code duplication, this logic should be extracted into a single, shared helper function. The defaultRuntimeMatrix() function in test.go could be moved to a shared location and reused here.

Comment thread internal/evaluator/evaluator.go Outdated

profiles := make(map[string][]optionProfile, len(optionKeys))
for _, key := range optionKeys {
values := slices.Clone(matrix.Options[key])
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The slice matrix.Options[key] is being cloned using slices.Clone, but the subsequent loop only reads from it. The clone is unnecessary and can be removed to simplify the code without changing the behavior.

Suggested change
values := slices.Clone(matrix.Options[key])
values := matrix.Options[key]

Comment thread internal/build/build.go
Comment on lines +401 to +406
if err != nil || info.IsDir() {
continue
}
sum, err := fileDigest(path)
if err != nil {
continue
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Errors from os.Stat and fileDigest are being ignored. While this might be acceptable if some input files are expected to be transient, it could also mask underlying problems during the build trace analysis. Consider logging these errors for debugging purposes or adding a comment to clarify why they are being intentionally ignored.

Comment thread internal/build/build.go
traceRoots, err := b.traceRoots(targets, mod, tmpSourceDir, installDir)
if err != nil {
return Result{}, err
}
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.

os.Chdir() changes the CWD for the entire process. This is not safe if any other goroutine relies on CWD (and the TODO at line 362 plans parallel builds). Additionally, the original directory is never restored after Chdir — after Build() returns, the process CWD points to a deleted temp directory.

Consider passing the source directory to OnBuild rather than mutating process-global state, or at minimum restoring the CWD in a defer.

Comment thread internal/build/build.go
Comment on lines +382 to +386
func collectTraceInputDigests(records []trace.Record, scope trace.Scope) map[string]string {
buildRoot := filepath.Clean(scope.BuildRoot)
if buildRoot == "" || len(records) == 0 {
return nil
}
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.

os.Clearenv() removes all environment variables process-wide. Any concurrent goroutine reading env vars during the Clearenv() + Setenv loop will see a partially restored (or empty) environment. The TODO on line 354 acknowledges this — until a sandbox is introduced, this is a latent concurrency hazard. Consider documenting that Build() must not be called concurrently.

Comment thread internal/build/build.go
Comment on lines +424 to +430
func fileDigest(path string) (string, error) {
data, err := os.ReadFile(path)
if err != nil {
return "", err
}
sum := sha256.Sum256(data)
return hex.EncodeToString(sum[:8]), nil
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.

Two issues:

  1. os.ReadFile loads the entire file into memory. For large build artifacts this is wasteful — streaming through sha256.New() with io.Copy would bound memory.
  2. The SHA-256 hash is silently truncated to 64 bits (sum[:8]). This significantly increases collision probability (~50% at 2^32 files). If acceptable for this use case, the truncation should be documented.

Comment thread cmd/llar/internal/test.go
Comment on lines +116 to +119
savedVerbose, savedOutput := makeVerbose, makeOutput
makeVerbose, makeOutput = testVerbose, ""
defer func() {
makeVerbose, makeOutput = savedVerbose, savedOutput
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.

testModule reaches across to mutate make.go's package-level globals (makeVerbose, makeOutput) to reuse buildModuleWithRunTest. This tight coupling through shared mutable state is fragile — if the probe loop or build were ever parallelized, this would race. Consider passing these as explicit parameters to buildModuleWithRunTest instead.

Comment thread cmd/llar/internal/test.go
Comment on lines +178 to +189
savedStdout, savedStderr := os.Stdout, os.Stderr
devNull, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0)
if err != nil {
return evaluator.ProbeResult{}, fmt.Errorf("failed to open devnull for %s: %w", moduleArg, err)
}
defer func() {
devNull.Close()
os.Stdout = savedStdout
os.Stderr = savedStderr
}()
os.Stdout = devNull
os.Stderr = devNull
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.

Global os.Stdout/os.Stderr redirection to /dev/null is not concurrency-safe. This same pattern also exists in make.go:147-158. Any goroutine writing to stdout/stderr (including panic handlers) during this window will have output silently lost. Consider passing io.Writer through the call chain rather than mutating process globals.

}

func allowPtraceAttach() (func(), error) {
err := unix.Prctl(unix.PR_SET_PTRACER, uintptr(unix.PR_SET_PTRACER_ANY), 0, 0, 0)
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.

PR_SET_PTRACER_ANY allows any same-UID process to ptrace the current process during the tracing window. A more targeted approach would use PR_SET_PTRACER with the specific strace child PID (start strace first, get its PID, then set the ptracer). If the chicken-and-egg problem prevents this, the security tradeoff should be documented with a comment here.

Comment thread internal/evaluator/evaluator.go Outdated
Comment on lines +1028 to +1036
func replaceScopeRootToken(token, root, placeholder string) string {
token = strings.ReplaceAll(token, root, placeholder)
if !strings.Contains(root, "$$TMP") {
return token
}
pattern := regexp.QuoteMeta(root)
pattern = strings.ReplaceAll(pattern, `\$\$TMP`, `[^/]+`)
re := regexp.MustCompile(pattern)
return re.ReplaceAllString(token, strings.ReplaceAll(placeholder, "$", "$$"))
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.

regexp.MustCompile is called inside replaceScopeRootToken, which is invoked from normalizeScopeToken on every path of every action during graph construction and fingerprinting — potentially tens of thousands of times. Regex compilation is expensive (parsing + NFA construction). Since the root values come from a small fixed set (SourceRoot, BuildRoot, InstallRoot), these regexps should be compiled once per scope and cached/reused.

Similarly, normalizeScopeToken (line 1002-1018) allocates and sorts a 3-element struct slice on every call — this could also be precomputed per scope.

Comment thread internal/trace/trace.go
Comment on lines +261 to +265
if !slices.Contains(state.current.Changes, path) {
state.current.Changes = append(state.current.Changes, path)
}
} else {
if !slices.Contains(state.current.Inputs, path) {
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.

slices.Contains is used to deduplicate Inputs and Changes on every open/rename/unlink syscall. This is O(k) per check where k grows with each file touch, yielding O(k^2) total per exec. A single compiler invocation can touch hundreds of files (include headers), making this quadratic behavior meaningful on large traces.

Consider using a map[string]struct{} side-set per Record for O(1) deduplication.

Comment thread internal/trace/trace.go
Comment on lines +610 to +615
flags := strings.ToUpper(strings.Join(call.args, " "))
return strings.Contains(flags, "O_WRONLY") ||
strings.Contains(flags, "O_RDWR") ||
strings.Contains(flags, "O_TRUNC") ||
strings.Contains(flags, "O_APPEND") ||
(strings.Contains(flags, "O_CREAT") && strings.Contains(flags, "O_EXCL"))
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.

isWriteOpen joins all call arguments (path, flags, mode) into one string and searches for flag names. This has two issues:

  1. Correctness: If a file path happens to contain O_WRONLY as a substring, this produces a false positive.
  2. Performance: This allocates a joined+uppercased string on every open/openat syscall — the most frequent events in a trace.

Consider examining only the flags argument directly (e.g., call.args[1] for open, call.args[2] for openat).

Comment thread internal/evaluator/evaluator.go Outdated
reBuildTmpPIDNoise = regexp.MustCompile(`\.tmp\.[0-9]+($|/)`)
)

func Watch(ctx context.Context, matrix formula.Matrix, probe ProbeFunc) ([]string, bool, error) {
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.

Watch is the primary public entry point for the orthogonal decomposition evaluator — the core algorithm of this PR. It deserves a doc comment explaining: what it does (probes matrix combinations, diffs action graphs, finds collision components, returns minimal combo set), the meaning of the trusted return value, and any constraints on the probe function.

@xgopilot
Copy link
Copy Markdown
Contributor

xgopilot bot commented Mar 15, 2026

Review Summary

Impressive feature — the orthogonal decomposition evaluator is architecturally well-conceived: tracing builds via strace, constructing action graphs, classifying tooling vs. business actions, then diffing to find colliding matrix options is a clever approach to minimizing test matrix execution.

Key concerns:

  • Process-global mutations (os.Chdir, os.Clearenv, os.Stdout/os.Stderr redirection) are the primary risk — they are not concurrency-safe and block the path to parallel builds.
  • Performance hot path in replaceScopeRootToken compiles a new regex on every call (invoked O(N×M) times during graph construction). Should be cached per scope.
  • O(n²) dedup via slices.Contains in the strace parser will degrade on large traces.
  • PR_SET_PTRACER_ANY scope could be narrowed; the security tradeoff should be documented.

See inline comments for details.

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.

1 participant