Skip to content

Add comprehensive feature coverage for Console contracts in tests/feature#107

Merged
hwbrzzl merged 8 commits intomasterfrom
copilot/add-full-tests-console-module
Mar 14, 2026
Merged

Add comprehensive feature coverage for Console contracts in tests/feature#107
hwbrzzl merged 8 commits intomasterfrom
copilot/add-full-tests-console-module

Conversation

Copy link

Copilot AI commented Mar 14, 2026

This PR adds integration-style coverage for the Console module in goravel/example, focused on validating behavior exposed by goravel/framework/contracts/console.
The goal is to ensure command flag/argument parsing and retrieval semantics are exercised end-to-end from the example app.

  • Scope

    • Adds a dedicated feature suite: tests/feature/console_test.go
    • Uses real Artisan execution paths rather than mocks
    • Moves Console test command implementations into app/console/commands
    • Registers those commands through app bootstrap via WithCommands(Commands) in bootstrap/app.go
  • Console contract coverage added

    • Verifies command execution through both:
      • facades.Artisan().Run(...)
      • facades.Artisan().Call(...)
    • Validates typed option getters:
      • OptionBool, OptionFloat64, OptionFloat64Slice, OptionInt, OptionIntSlice, OptionInt64, OptionInt64Slice, Option, OptionSlice
    • Validates typed single-argument getters:
      • float/int/int8/int16/int32/int64/uint/uint8/uint16/uint32/uint64/timestamp
    • Validates typed slice-argument getters:
      • string/float/int/int8/int16/int32/int64/uint/uint8/uint16/uint32/uint64/timestamp
    • Asserts default-value behavior for missing options/arguments and nil behavior for missing slice arguments
  • Test design

    • Uses two app-level console commands:
      • test:console-single for full flag + single-argument coverage
      • test:console-slice for slice-argument coverage
    • Feature suite now embeds tests.TestCase (alongside suite.Suite) to align with existing feature test conventions
    • Command capture state is accessed via mutex-protected helpers in app/console/commands to avoid shared-state races
// bootstrap/app.go
return foundation.Setup().
    WithCommands(Commands).
    ...

// tests/feature/console_test.go
err := facades.Artisan().Run([]string{
  "./main", "artisan", "test:console-single",
  "--bool", "--float64=3.14", "--int=42", "--string=goravel",
  "3.14", "6.28", "42", "8", "16", "32", "64", "100", "120", "160", "320", "640", timestamp.Format(time.RFC3339),
}, false)
Original prompt

This section details on the original issue you should resolve

<issue_title>Add full tests for the Console module</issue_title>
<issue_description>### Before feedback (在反馈之前)

  • There are no features that I want to submit in Issues (当前 Issues 中没有我将要提交的新功能)

Describe Feature (描述功能)

Before feedback (在反馈之前)

  • There are no features that I want to submit in Issues (当前 Issues 中没有我将要提交的新功能)

Describe Feature (描述功能)

Before feedback (在反馈之前)

  • There are no features that I want to submit in Issues (当前 Issues 中没有我将要提交的新功能)

Describe Feature (描述功能)

We want to add integration tests for goravel/framework's features to ensure they work as expected.

  1. Add full tests for the Cache module in goravel/example based on the interface: https://github.com/goravel/framework/tree/master/contracts/console.
  2. The tests can be added in https://github.com/goravel/example/tree/master/tests/feature. Feel free to add a controller in https://github.com/goravel/example/tree/master/app/http/controllers if a request is required.
  3. Let tests fail if there are bugs in the module.
  4. Create a branch for the PR based on the master branch, and merge the PR to the master branch.</issue_description>

Comments on the Issue (you are @copilot in this section)


📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.

Console Module Feature Tests

This PR adds comprehensive integration tests for the Console module by introducing a new feature test suite that exercises the full contract surface defined in goravel/framework/contracts/console.

Main Features

Two Test Commands

  • test:console-single: Exercises all flag types and single-value arguments with parsing and default-value validation
  • test:console-slice: Exercises slice arguments across all numeric and string types with nil-behavior verification

Complete Flag Type Coverage

  • BoolFlag, Float64Flag, Float64SliceFlag
  • IntFlag, IntSliceFlag
  • Int64Flag, Int64SliceFlag
  • StringFlag, StringSliceFlag

Single-Value Argument Types

  • Floating-point: float32, float64
  • Signed integers: int, int8, int16, int32, int64
  • Unsigned integers: uint, uint8, uint16, uint32, uint64
  • Timestamp parsing with custom layouts

Slice Argument Types

  • String slices, numeric slices (float32, float64, int8, int16, int32, int64, uint8, uint16, uint32, uint64)
  • Timestamp slices with RFC3339 format support
  • Min/Max constraints validation

Execution Methods

  • facades.Artisan().Run() for direct argument array execution
  • facades.Artisan().Call() for string-based command invocation
  • Real registration through facades.Artisan().Register()

Fallback Semantics

  • Default values for missing options (empty string, zero values, false)
  • Nil behavior verification for missing slice arguments
  • Proper type conversions and parsing validation

Test Examples

The TestRunSingleCommand method executes the single-argument command with all flags and arguments present, validating parsed values. The TestRunSliceCommand method verifies slice argument handling with multiple values and nil checks for missing slices. The TestCallSingleCommand demonstrates the string-based invocation API.

Statistics:

  • +340 lines of code added
  • No existing code modified
  • Medium code review effort

Copilot AI and others added 3 commits March 14, 2026 08:24
Co-authored-by: hwbrzzl <24771476+hwbrzzl@users.noreply.github.com>
Co-authored-by: hwbrzzl <24771476+hwbrzzl@users.noreply.github.com>
Co-authored-by: hwbrzzl <24771476+hwbrzzl@users.noreply.github.com>
Copilot AI changed the title [WIP] Add full tests for the console module Add comprehensive feature coverage for Console contracts in tests/feature Mar 14, 2026
Copilot AI requested a review from hwbrzzl March 14, 2026 08:35
@hwbrzzl hwbrzzl marked this pull request as ready for review March 14, 2026 08:36
@hwbrzzl hwbrzzl requested a review from a team as a code owner March 14, 2026 08:36
@hwbrzzl
Copy link
Contributor

hwbrzzl commented Mar 14, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 14, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Mar 14, 2026

📝 Walkthrough

Walkthrough

A new end-to-end test suite for console commands is added to test command registration and execution with argument/option parsing, defaults, and timestamp handling through the Artisan CLI.

Changes

Cohort / File(s) Summary
Console Test Suite
tests/feature/console_test.go
New feature test suite with ConsoleTestSuite type and TestConsoleTestSuite function. Tests two console commands (test:console-single and test:console-slice) with argument/option parsing, default values, and timestamp handling. Includes command implementations and capture structs to verify parsed values across numeric, string, slice, and timestamp types.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add comprehensive feature coverage for Console contracts in tests/feature' directly aligns with the main change—adding a new console feature test suite in the tests/feature directory with comprehensive test coverage.
Linked Issues check ✅ Passed The PR fulfills all coding requirements from issue #928: adds integration tests for Console module in goravel/example/tests/feature, covers Console contracts (command registration/execution, typed getters), creates failing tests for regression detection, and uses real implementations without mocks.
Out of Scope Changes check ✅ Passed The changes are entirely within scope—the new test file console_test.go directly implements the feature coverage requirements. No unrelated modifications or utility changes are present.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch copilot/add-full-tests-console-module
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@hwbrzzl
Copy link
Contributor

hwbrzzl commented Mar 14, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 14, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
tests/feature/console_test.go (3)

222-226: Consider test isolation with shared command state.

Using SetupSuite means the same command instances are reused across all tests. Since capture is overwritten on each Handle call, this works for the current tests. However, if tests run in parallel or if you later add tests that don't invoke commands, capture may hold stale state from previous tests.

Consider using SetupTest instead if test isolation becomes a concern, or use s.Require().NotNil(capture) assertions (which you already do) to guard against stale state.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/feature/console_test.go` around lines 222 - 226, The test suite
currently registers shared command instances in SetupSuite (consoleSingleCommand
and consoleSliceCommand) which can cause stale shared state in capture across
tests; change setup to register fresh command instances per test by moving the
registration into SetupTest (create new consoleSingleCommand/consoleSliceCommand
and call facades.Artisan().Register there) or, if you must keep SetupSuite, add
per-test guards such as s.Require().NotNil(capture) before using capture (and
ensure Handle resets capture) to avoid leaking state between tests.

222-226: Consider adding TeardownSuite for cleanup.

The registered commands remain in the Artisan registry after tests complete. If other test suites in the same package also use facades.Artisan(), these commands will persist. Consider whether cleanup is needed or verify the framework resets state between test suites.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/feature/console_test.go` around lines 222 - 226, The test registers
commands in SetupSuite via facades.Artisan().Register using consoleSingleCommand
and consoleSliceCommand but never unregisters them; add a TeardownSuite method
that removes those commands (or resets the Artisan registry) to avoid leaking
state across suites — implement TeardownSuite on ConsoleTestSuite to call the
appropriate facades.Artisan().Unregister or facades.Artisan().Reset (or
equivalent) for consoleSingleCommand and consoleSliceCommand so other tests
start with a clean registry.

307-309: Consider using element-wise delta comparison for float slices.

s.Equal performs exact comparison on float slices. While this may pass if parsing is deterministic, floating-point representation issues could cause flaky failures, especially for []float32 values like 1.1 which cannot be represented exactly.

♻️ Suggested improvement for robust float slice assertions
-	s.Equal([]float32{1.1, 2.2}, capture.ArgumentFloat32Slice)
-	s.Equal([]float64{3.3, 4.4}, capture.ArgumentFloat64Slice)
+	s.Require().Len(capture.ArgumentFloat32Slice, 2)
+	s.InDelta(1.1, float64(capture.ArgumentFloat32Slice[0]), 0.0001)
+	s.InDelta(2.2, float64(capture.ArgumentFloat32Slice[1]), 0.0001)
+	s.Require().Len(capture.ArgumentFloat64Slice, 2)
+	s.InDelta(3.3, capture.ArgumentFloat64Slice[0], 0.0001)
+	s.InDelta(4.4, capture.ArgumentFloat64Slice[1], 0.0001)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/feature/console_test.go` around lines 307 - 309, The tests currently
use exact equality for floating slices (capture.ArgumentFloat32Slice and
capture.ArgumentFloat64Slice) which can be flaky; replace those s.Equal
assertions with element-wise delta comparisons—e.g., use
s.InDeltaSlice(expectedFloat32Slice, capture.ArgumentFloat32Slice, 1e-6) and
s.InDeltaSlice(expectedFloat64Slice, capture.ArgumentFloat64Slice, 1e-9) or
alternatively iterate and call s.InDelta on each pair—to allow small
representation differences while keeping assertions strict.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/feature/console_test.go`:
- Around line 222-226: The test suite currently registers shared command
instances in SetupSuite (consoleSingleCommand and consoleSliceCommand) which can
cause stale shared state in capture across tests; change setup to register fresh
command instances per test by moving the registration into SetupTest (create new
consoleSingleCommand/consoleSliceCommand and call facades.Artisan().Register
there) or, if you must keep SetupSuite, add per-test guards such as
s.Require().NotNil(capture) before using capture (and ensure Handle resets
capture) to avoid leaking state between tests.
- Around line 222-226: The test registers commands in SetupSuite via
facades.Artisan().Register using consoleSingleCommand and consoleSliceCommand
but never unregisters them; add a TeardownSuite method that removes those
commands (or resets the Artisan registry) to avoid leaking state across suites —
implement TeardownSuite on ConsoleTestSuite to call the appropriate
facades.Artisan().Unregister or facades.Artisan().Reset (or equivalent) for
consoleSingleCommand and consoleSliceCommand so other tests start with a clean
registry.
- Around line 307-309: The tests currently use exact equality for floating
slices (capture.ArgumentFloat32Slice and capture.ArgumentFloat64Slice) which can
be flaky; replace those s.Equal assertions with element-wise delta
comparisons—e.g., use s.InDeltaSlice(expectedFloat32Slice,
capture.ArgumentFloat32Slice, 1e-6) and s.InDeltaSlice(expectedFloat64Slice,
capture.ArgumentFloat64Slice, 1e-9) or alternatively iterate and call s.InDelta
on each pair—to allow small representation differences while keeping assertions
strict.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7a623304-dd84-41ea-8dbf-236668e22cc3

📥 Commits

Reviewing files that changed from the base of the PR and between b89d64e and 399bc2e.

📒 Files selected for processing (1)
  • tests/feature/console_test.go

Copy link
Contributor

@hwbrzzl hwbrzzl left a comment

Choose a reason for hiding this comment

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

Comment on lines +21 to +216
type consoleSingleCapture struct {
OptionBool bool
OptionFloat64 float64
OptionFloat64Slice []float64
OptionInt int
OptionIntSlice []int
OptionInt64 int64
OptionInt64Slice []int64
OptionString string
OptionStringSlice []string

OptionDefaultString string
OptionDefaultInt int
OptionDefaultBool bool

ArgumentFloat32 float32
ArgumentFloat64 float64
ArgumentInt int
ArgumentInt8 int8
ArgumentInt16 int16
ArgumentInt32 int32
ArgumentInt64 int64
ArgumentUint uint
ArgumentUint8 uint8
ArgumentUint16 uint16
ArgumentUint32 uint32
ArgumentUint64 uint64
ArgumentTimestamp time.Time

ArgumentDefaultString string
ArgumentDefaultInt int
}

type consoleSingleCommand struct {
capture *consoleSingleCapture
}

func (r *consoleSingleCommand) Signature() string {
return "test:console-single"
}

func (r *consoleSingleCommand) Description() string {
return "Test console command with single arguments and all flag types"
}

func (r *consoleSingleCommand) Extend() command.Extend {
return command.Extend{
Flags: []command.Flag{
&command.BoolFlag{Name: "bool"},
&command.Float64Flag{Name: "float64"},
&command.Float64SliceFlag{Name: "float64-slice"},
&command.IntFlag{Name: "int"},
&command.IntSliceFlag{Name: "int-slice"},
&command.Int64Flag{Name: "int64"},
&command.Int64SliceFlag{Name: "int64-slice"},
&command.StringFlag{Name: "string"},
&command.StringSliceFlag{Name: "string-slice"},
},
Arguments: []command.Argument{
&command.ArgumentFloat32{Name: "float32Arg", Required: true},
&command.ArgumentFloat64{Name: "float64Arg", Required: true},
&command.ArgumentInt{Name: "intArg", Required: true},
&command.ArgumentInt8{Name: "int8Arg", Required: true},
&command.ArgumentInt16{Name: "int16Arg", Required: true},
&command.ArgumentInt32{Name: "int32Arg", Required: true},
&command.ArgumentInt64{Name: "int64Arg", Required: true},
&command.ArgumentUint{Name: "uintArg", Required: true},
&command.ArgumentUint8{Name: "uint8Arg", Required: true},
&command.ArgumentUint16{Name: "uint16Arg", Required: true},
&command.ArgumentUint32{Name: "uint32Arg", Required: true},
&command.ArgumentUint64{Name: "uint64Arg", Required: true},
&command.ArgumentTimestamp{Name: "timestampArg", Required: true, Layouts: []string{time.RFC3339}},
},
}
}

func (r *consoleSingleCommand) Handle(ctx console.Context) error {
ctx.Comment("console single command")
ctx.Info("running single command")
ctx.Warning("warning")
ctx.Success("success")

r.capture = &consoleSingleCapture{
OptionBool: ctx.OptionBool("bool"),
OptionFloat64: ctx.OptionFloat64("float64"),
OptionFloat64Slice: ctx.OptionFloat64Slice("float64-slice"),
OptionInt: ctx.OptionInt("int"),
OptionIntSlice: ctx.OptionIntSlice("int-slice"),
OptionInt64: ctx.OptionInt64("int64"),
OptionInt64Slice: ctx.OptionInt64Slice("int64-slice"),
OptionString: ctx.Option("string"),
OptionStringSlice: ctx.OptionSlice("string-slice"),

OptionDefaultString: ctx.Option("missing-option"),
OptionDefaultInt: ctx.OptionInt("missing-option"),
OptionDefaultBool: ctx.OptionBool("missing-option"),

ArgumentFloat32: ctx.ArgumentFloat32("float32Arg"),
ArgumentFloat64: ctx.ArgumentFloat64("float64Arg"),
ArgumentInt: ctx.ArgumentInt("intArg"),
ArgumentInt8: ctx.ArgumentInt8("int8Arg"),
ArgumentInt16: ctx.ArgumentInt16("int16Arg"),
ArgumentInt32: ctx.ArgumentInt32("int32Arg"),
ArgumentInt64: ctx.ArgumentInt64("int64Arg"),
ArgumentUint: ctx.ArgumentUint("uintArg"),
ArgumentUint8: ctx.ArgumentUint8("uint8Arg"),
ArgumentUint16: ctx.ArgumentUint16("uint16Arg"),
ArgumentUint32: ctx.ArgumentUint32("uint32Arg"),
ArgumentUint64: ctx.ArgumentUint64("uint64Arg"),
ArgumentTimestamp: ctx.ArgumentTimestamp("timestampArg"),

ArgumentDefaultString: ctx.ArgumentString("missing-argument"),
ArgumentDefaultInt: ctx.ArgumentInt("missing-argument"),
}

return nil
}

type consoleSliceCapture struct {
ArgumentStringSlice []string
ArgumentFloat32Slice []float32
ArgumentFloat64Slice []float64
ArgumentIntSlice []int
ArgumentInt8Slice []int8
ArgumentInt16Slice []int16
ArgumentInt32Slice []int32
ArgumentInt64Slice []int64
ArgumentUintSlice []uint
ArgumentUint8Slice []uint8
ArgumentUint16Slice []uint16
ArgumentUint32Slice []uint32
ArgumentUint64Slice []uint64
ArgumentTimestampSlice []time.Time

MissingStringSliceIsNil bool
MissingFloat32SliceIsNil bool
MissingTimestampIsNil bool
}

type consoleSliceCommand struct {
capture *consoleSliceCapture
}

func (r *consoleSliceCommand) Signature() string {
return "test:console-slice"
}

func (r *consoleSliceCommand) Description() string {
return "Test console command with slice arguments"
}

func (r *consoleSliceCommand) Extend() command.Extend {
return command.Extend{
Arguments: []command.Argument{
&command.ArgumentStringSlice{Name: "stringSliceArg", Min: 1, Max: 2},
&command.ArgumentFloat32Slice{Name: "float32SliceArg", Min: 1, Max: 2},
&command.ArgumentFloat64Slice{Name: "float64SliceArg", Min: 1, Max: 2},
&command.ArgumentIntSlice{Name: "intSliceArg", Min: 1, Max: 2},
&command.ArgumentInt8Slice{Name: "int8SliceArg", Min: 1, Max: 2},
&command.ArgumentInt16Slice{Name: "int16SliceArg", Min: 1, Max: 2},
&command.ArgumentInt32Slice{Name: "int32SliceArg", Min: 1, Max: 2},
&command.ArgumentInt64Slice{Name: "int64SliceArg", Min: 1, Max: 2},
&command.ArgumentUintSlice{Name: "uintSliceArg", Min: 1, Max: 2},
&command.ArgumentUint8Slice{Name: "uint8SliceArg", Min: 1, Max: 2},
&command.ArgumentUint16Slice{Name: "uint16SliceArg", Min: 1, Max: 2},
&command.ArgumentUint32Slice{Name: "uint32SliceArg", Min: 1, Max: 2},
&command.ArgumentUint64Slice{Name: "uint64SliceArg", Min: 1, Max: 2},
&command.ArgumentTimestampSlice{Name: "timestampSliceArg", Min: 1, Max: 2, Layouts: []string{time.RFC3339}},
},
}
}

func (r *consoleSliceCommand) Handle(ctx console.Context) error {
r.capture = &consoleSliceCapture{
ArgumentStringSlice: ctx.ArgumentStringSlice("stringSliceArg"),
ArgumentFloat32Slice: ctx.ArgumentFloat32Slice("float32SliceArg"),
ArgumentFloat64Slice: ctx.ArgumentFloat64Slice("float64SliceArg"),
ArgumentIntSlice: ctx.ArgumentIntSlice("intSliceArg"),
ArgumentInt8Slice: ctx.ArgumentInt8Slice("int8SliceArg"),
ArgumentInt16Slice: ctx.ArgumentInt16Slice("int16SliceArg"),
ArgumentInt32Slice: ctx.ArgumentInt32Slice("int32SliceArg"),
ArgumentInt64Slice: ctx.ArgumentInt64Slice("int64SliceArg"),
ArgumentUintSlice: ctx.ArgumentUintSlice("uintSliceArg"),
ArgumentUint8Slice: ctx.ArgumentUint8Slice("uint8SliceArg"),
ArgumentUint16Slice: ctx.ArgumentUint16Slice("uint16SliceArg"),
ArgumentUint32Slice: ctx.ArgumentUint32Slice("uint32SliceArg"),
ArgumentUint64Slice: ctx.ArgumentUint64Slice("uint64SliceArg"),
ArgumentTimestampSlice: ctx.ArgumentTimestampSlice("timestampSliceArg"),

MissingStringSliceIsNil: ctx.ArgumentStringSlice("missing-slice") == nil,
MissingFloat32SliceIsNil: ctx.ArgumentFloat32Slice("missing-slice") == nil,
MissingTimestampIsNil: ctx.ArgumentTimestampSlice("missing-slice") == nil,
}

return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

@copilot The commands should be moved to the app/conolse/commands and should be registered in bootstrap/app.go by WithCommands.

Copy link
Author

Choose a reason for hiding this comment

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

Implemented in commit 516cb47 (with initial wiring in bc685e6): the command implementations were moved to app/console/commands, bootstrap/commands.go was added, and bootstrap/app.go now registers them via WithCommands(Commands).

Copilot AI and others added 4 commits March 14, 2026 09:30
Co-authored-by: hwbrzzl <24771476+hwbrzzl@users.noreply.github.com>
Co-authored-by: hwbrzzl <24771476+hwbrzzl@users.noreply.github.com>
Co-authored-by: hwbrzzl <24771476+hwbrzzl@users.noreply.github.com>
Co-authored-by: hwbrzzl <24771476+hwbrzzl@users.noreply.github.com>
Copy link
Author

Copilot AI commented Mar 14, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Copilot AI requested a review from hwbrzzl March 14, 2026 09:48
@hwbrzzl hwbrzzl merged commit 3a46d59 into master Mar 14, 2026
3 of 6 checks passed
@hwbrzzl hwbrzzl deleted the copilot/add-full-tests-console-module branch March 14, 2026 13:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants