Skip to content

feat(exec): detect compiler activity during process startup#119

Open
moshloop wants to merge 1 commit into
mainfrom
feat/pluggable-live-renderer
Open

feat(exec): detect compiler activity during process startup#119
moshloop wants to merge 1 commit into
mainfrom
feat/pluggable-live-renderer

Conversation

@moshloop

@moshloop moshloop commented Jun 16, 2026

Copy link
Copy Markdown
Member

What

  • Add compiler and linker detection to distinguish compilation phase from startup phase
  • Introduce StatusCompiling to track when build tools are actively running
  • Update watchPorts function to accept compilationDetector callback
  • Manage three startup states: compiling → starting → running

Why

  • Prevent premature promotion to StatusRunning during builds
  • Allow long compilation times without timing out
  • Improve startup lifecycle management

Notes

  • Compiler activity resets the grace period timer
  • Detected port immediately promotes to running regardless of compilation state

Summary by CodeRabbit

  • New Features
    • Introduced automatic detection of compiler and linker activity during supervised process startup, providing better visibility into build phases.
    • Added new compilation status to the process lifecycle, improving state tracking for applications that require build steps before execution.
    • Enhanced process supervision to gracefully transition from compilation to running state after activity completes.

Add compiler and linker detection to distinguish compilation phase from startup phase. Introduces StatusCompiling to track when build tools are actively running, preventing premature promotion to StatusRunning. The watchPorts function now accepts a compilationDetector callback and manages three startup states: compiling → starting → running. Compiler activity resets the grace period timer, allowing long builds to complete without timing out. A detected port immediately promotes to running regardless of compilation state.

Refs: compiler detection for improved startup lifecycle management
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds a StatusCompiling lifecycle status and a new exec/compiler.go module that identifies compiler/linker processes by normalized executable name or command-line arguments. The watchPorts state machine in exec/supervise_loop.go is extended to transition through StatusCompiling when compilation activity is detected but no ports are yet bound, using a waitingSince grace window before promoting to StatusRunning.

Changes

Compiler detection and watchPorts state machine

Layer / File(s) Summary
StatusCompiling constant and compiler detection module
exec/supervised.go, exec/compiler.go
Adds StatusCompiling Status = "compiling" to the Status enum and introduces exec/compiler.go, which scans PIDs via collectPids, normalizes executable names and command-line arguments, and returns true when any process matches a known compiler or linker basename.
watchPorts state machine with compilationDetector
exec/supervise_loop.go
Defines the compilationDetector callback type, wires detectCompilers into runLoop, and rewrites the watchPorts inner loop to track waitingSince, invoke the compilation detector when no ports are observed, and branch across StatusCompiling, StatusStarting, and StatusRunning transitions. Expands promoteIfStarting to promote StatusCompiling runs when port detection must stop early.
Test coverage for compilation detection and state transitions
exec/supervised_test.go
Updates existing watchPorts test calls to pass the new compile-detector argument, adds state-transition tests using atomic.Bool to drive StatusCompilingStatusStartingStatusRunning, and adds a compiler startup detection suite asserting isCompilerExecutable and isCompilerCommandLine matching rules.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description provides a clear What/Why/Notes structure explaining the changes, but lacks required checklist items from the template (Type of Change, Testing, and Checklist sections are not addressed). Complete the missing template sections: mark the Type of Change (New feature), confirm testing status, and address the Checklist items to fully comply with the repository template.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(exec): detect compiler activity during process startup' clearly and concisely describes the main change—adding compiler detection during process startup.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/pluggable-live-renderer
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/pluggable-live-renderer

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 and usage tips.

@github-actions

Copy link
Copy Markdown

Gavel summary

Source Pass Fail Skip Duration
github.com/flanksource/clicky 47 1 0 17.0s
ai 9 0 0 402.076µs
api 125 0 12 24ms
cache 12 0 0 10ms
clicky 98 0 0 7.4s
exec 91 0 1 8.7s
flags 20 0 0 1ms
formatters 26 0 0 4ms
github.com/flanksource/clicky/ai 10 0 0 50ms
github.com/flanksource/clicky/aichat 41 0 0 -
github.com/flanksource/clicky/api 235 0 0 110ms
github.com/flanksource/clicky/api/tailwind 427 0 0 -
github.com/flanksource/clicky/docs 19 0 0 -
github.com/flanksource/clicky/examples/enitity 1 0 0 -
github.com/flanksource/clicky/exec 3 0 0 370ms
github.com/flanksource/clicky/flags 32 0 0 20ms
github.com/flanksource/clicky/formatters 50 0 0 10ms
github.com/flanksource/clicky/formatters/http 38 0 0 -
github.com/flanksource/clicky/formatters/pdf 0 0 1 -
github.com/flanksource/clicky/formatters/tests 202 0 1 1m0s
github.com/flanksource/clicky/internal/gumchoose 2 0 0 -
github.com/flanksource/clicky/lint 4 0 0 -
github.com/flanksource/clicky/mcp 34 0 0 30ms
github.com/flanksource/clicky/middleware 31 0 0 -
github.com/flanksource/clicky/rpc 188 0 1 10ms
github.com/flanksource/clicky/task 82 0 0 15.8s
lint 6 0 0 6.1s
metrics 7 0 0 5ms
middleware 38 0 0 8ms
task 6 0 0 45ms
tests 11 0 47 11ms
text 78 0 0 310ms
valkey 22 0 0 46ms

Totals: 1995 passed · 1 failed · 63 skipped · 1m57s

Failing tests

github.com/flanksource/clicky — TestPromptMultiSelectConfirmsSelections

prompt_test.go:268: 
        	Error Trace:	/home/runner/work/clicky/clicky/prompt_test.go:268
        	Error:      	"\rPick checks\r\n> ○ alpha  \r\n  ○ beta   \r\n  ○ gamma  \r\n           \r\n  ◉ alpha  \r\n> ○ beta   \r\n\n\r\n\n> ◉ beta   \r\n\n\r" does not contain "RESULT=a...
        	Test:       	TestPromptMultiSelectConfirmsSelections

View full results

@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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@exec/compiler.go`:
- Around line 34-50: The detectCompilers function silently ignores all errors
from gopsutil probes (gops.NewProcess, proc.Name, proc.Exe, proc.CmdlineSlice)
by using continue statements and always returns nil error regardless of
inspection failures. Track errors during the iteration through collectPids
results, and when compiler detection has no visibility into the process tree
(all probes fail), return an appropriate error instead of nil so callers can
distinguish between "no compilers found" and "couldn't inspect processes". This
ensures the caller doesn't prematurely advance startup state when inspection
failures occur.
🪄 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: CHILL

Plan: Pro

Run ID: 21e3e8df-63fe-40e8-b4b9-6c478b1c7cd0

📥 Commits

Reviewing files that changed from the base of the PR and between 3e7da2d and 9ba901b.

📒 Files selected for processing (4)
  • exec/compiler.go
  • exec/supervise_loop.go
  • exec/supervised.go
  • exec/supervised_test.go

Comment thread exec/compiler.go
Comment on lines +34 to +50
func detectCompilers(root int32) (bool, error) {
for _, pid := range collectPids(root) {
proc, err := gops.NewProcess(pid)
if err != nil {
continue
}
if name, err := proc.Name(); err == nil && isCompilerExecutable(name) {
return true, nil
}
if exe, err := proc.Exe(); err == nil && isCompilerExecutable(exe) {
return true, nil
}
if args, err := proc.CmdlineSlice(); err == nil && isCompilerCommandLine(args) {
return true, nil
}
}
return false, 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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Surface probe failures when compiler detection has no visibility.

detectCompilers currently swallows all gopsutil probe errors and always returns nil error. When inspection fails across the tree, the caller treats that as “not compiling”, which can advance startup state prematurely.

Proposed fix
 func detectCompilers(root int32) (bool, error) {
+	var firstErr error
+	visible := false
 	for _, pid := range collectPids(root) {
 		proc, err := gops.NewProcess(pid)
 		if err != nil {
+			if firstErr == nil {
+				firstErr = err
+			}
 			continue
 		}
-		if name, err := proc.Name(); err == nil && isCompilerExecutable(name) {
+		if name, err := proc.Name(); err == nil {
+			visible = true
+			if isCompilerExecutable(name) {
+				return true, nil
+			}
+		} else if firstErr == nil {
+			firstErr = err
+		}
+		if exe, err := proc.Exe(); err == nil {
+			visible = true
+			if isCompilerExecutable(exe) {
+				return true, nil
+			}
+		} else if firstErr == nil {
+			firstErr = err
+		}
+		if args, err := proc.CmdlineSlice(); err == nil {
+			visible = true
+			if isCompilerCommandLine(args) {
+				return true, nil
+			}
+		} else if firstErr == nil {
+			firstErr = err
+		}
-			return true, nil
-		}
-		if exe, err := proc.Exe(); err == nil && isCompilerExecutable(exe) {
-			return true, nil
-		}
-		if args, err := proc.CmdlineSlice(); err == nil && isCompilerCommandLine(args) {
-			return true, nil
-		}
 	}
+	if !visible && firstErr != nil {
+		return false, firstErr
+	}
 	return false, nil
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func detectCompilers(root int32) (bool, error) {
for _, pid := range collectPids(root) {
proc, err := gops.NewProcess(pid)
if err != nil {
continue
}
if name, err := proc.Name(); err == nil && isCompilerExecutable(name) {
return true, nil
}
if exe, err := proc.Exe(); err == nil && isCompilerExecutable(exe) {
return true, nil
}
if args, err := proc.CmdlineSlice(); err == nil && isCompilerCommandLine(args) {
return true, nil
}
}
return false, nil
func detectCompilers(root int32) (bool, error) {
var firstErr error
visible := false
for _, pid := range collectPids(root) {
proc, err := gops.NewProcess(pid)
if err != nil {
if firstErr == nil {
firstErr = err
}
continue
}
if name, err := proc.Name(); err == nil {
visible = true
if isCompilerExecutable(name) {
return true, nil
}
} else if firstErr == nil {
firstErr = err
}
if exe, err := proc.Exe(); err == nil {
visible = true
if isCompilerExecutable(exe) {
return true, nil
}
} else if firstErr == nil {
firstErr = err
}
if args, err := proc.CmdlineSlice(); err == nil {
visible = true
if isCompilerCommandLine(args) {
return true, nil
}
} else if firstErr == nil {
firstErr = err
}
}
if !visible && firstErr != nil {
return false, firstErr
}
return false, nil
}
🤖 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 `@exec/compiler.go` around lines 34 - 50, The detectCompilers function silently
ignores all errors from gopsutil probes (gops.NewProcess, proc.Name, proc.Exe,
proc.CmdlineSlice) by using continue statements and always returns nil error
regardless of inspection failures. Track errors during the iteration through
collectPids results, and when compiler detection has no visibility into the
process tree (all probes fail), return an appropriate error instead of nil so
callers can distinguish between "no compilers found" and "couldn't inspect
processes". This ensures the caller doesn't prematurely advance startup state
when inspection failures occur.

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