Skip to content

Hopper elevator#86

Closed
maiKuneho wants to merge 29 commits into
mainfrom
hopper-elevator
Closed

Hopper elevator#86
maiKuneho wants to merge 29 commits into
mainfrom
hopper-elevator

Conversation

@maiKuneho
Copy link
Copy Markdown
Contributor

No description provided.

arcadeArchitect and others added 29 commits March 17, 2026 19:34
…ts, refine constants, relocate subsystem current/goal states into respective subsystem files, add booleans in RobotContainer.java to switch between real/io implementations
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 28, 2026

Summary by CodeRabbit

  • New Features

    • Added hopper elevator subsystem for improved height management.
    • Introduced guided launch drive command for trajectory optimization.
  • Improvements

    • Consolidated shooter subsystems for simplified control.
    • Updated vision camera calibration for improved accuracy.
    • Enhanced motor thermal monitoring and disconnect alerts.
    • Optimized motor configurations and mechanical tuning.
  • Refactoring

    • Removed turret tracking system.
    • Streamlined intake pivot and shooter hood control interfaces.

Walkthrough

The PR consolidates multi-instance shooter hardware (left/right flywheel, hood, turret) into unified single instances, removes the turret subsystem entirely, introduces a new HopperElevator subsystem to replace turret elevator logic, refactors RobotState to track odometry-based poses instead of subsystem states, adds launching functionality with drive-angle closed-loop control in DriveCommands, updates vision camera calibration parameters, and modifies Constants with revised device IDs and mechanism configurations.

Changes

Cohort / File(s) Summary
Build/Environment Settings
.vscode/settings.json
Increased Java JDT Language Server max heap size from 2G to 4G.
Constants Device & Configuration Overhaul
src/main/java/org/team5924/frc2026/Constants.java
Removed Translation3d import; split GenericRoller.CONFIG into CLOCKWISE_CONFIG and COUNTERCLOCKWISE_CONFIG; reduced IntakePivot motor current limits (120A→60A) and disabled software soft-limits; renamed/unified shooter classes (GeneralShooterHoodShooterHood, GeneralFlywheelFlywheel); added new CAN IDs for multiple components; added new HopperElevator inner class with motor/CANCoder IDs and mechanism configuration; removed left/right-specific turret/shooter constants and per-side classes; updated CTRE CANcoder feedback/magnet offset configuration.
Robot Lifecycle & Initialization
src/main/java/org/team5924/frc2026/Robot.java
Added LaunchCalculator import; moved low-battery alert reset logic to constructor (runs only when DriverStation.isEnabled()); added periodic call to LaunchCalculator.getInstance().clearLaunchingParameters() in robotPeriodic().
Container Hardware Wiring
src/main/java/org/team5924/frc2026/RobotContainer.java
Consolidated shooter subsystems from left/right instances to single shooterHood and flywheel objects; removed turret subsystem wiring; refactored REAL/SIM/REPLAY mode initialization to use new real* boolean flags for conditionally instantiating concrete vs. stub IO; simplified button bindings to use shared driveController for intake and shooter control via new joystickDriveWhileLaunching scheme.
Robot State Tracking
src/main/java/org/team5924/frc2026/RobotState.java
Removed estimatedPose field and updated getRotation() to use odometryPose; removed subsystem state fields (intakeState, intakePivotState, hopperState, indexerState, *TurretState, *FlywheelState, *ShooterHoodState); added isFlywheelAtSetpoint boolean field.
Drive Command Infrastructure
src/main/java/org/team5924/frc2026/commands/drive/DriveCommands.java
Added tuning-backed launch constants (LoggedTunableNumber PID gains, tolerances); introduced joystickDriveWhileLaunching() with LaunchCalculator-driven angular velocity output, lookahead polar velocity constraints, and COR offset transforms; added atLaunchGoal() status check gated on DriverStation.isEnabled().
Autonomous & Pose-based Commands
src/main/java/org/team5924/frc2026/commands/drive/DriveToPose.java, src/main/java/org/team5924/frc2026/commands/AutoBuilder.java
Switched pose supplier from getEstimatedPose() to getOdometryPose() for control feedback and termination checks.
Shooter Command Simplification
src/main/java/org/team5924/frc2026/commands/shooter/AutoScoreCommands.java, src/main/java/org/team5924/frc2026/commands/shooter/ManualShooterCommands.java
Removed turret parameter and logic from runTrackTargetCommand() (signature changed from accepting turret to only hood/flywheel); removed manualTurret() command; updated manualShooterHood() to pass DoubleSupplier directly to setInput().
Flywheel Subsystem Unification
src/main/java/org/team5924/frc2026/subsystems/flywheel/Flywheel.java, src/main/java/org/team5924/frc2026/subsystems/flywheel/FlywheelIO*
Removed left/right dual-instance logic (isLeft, per-side state handling); introduced unified currentState derived from goalState; renamed states (MANUAL/SETPOINTMANUAL_SETPOINT); added setAutoInput() with clamping; expanded motor/thermal alerting from single instances to Alert[4] arrays for per-motor tracking; unified TalonFX configuration with single shared tuning parameters; updated inputs to use arrays (motorConnected[4], tempCelsius[4]).
ShooterHood Subsystem Unification
src/main/java/org/team5924/frc2026/subsystems/pivots/shooterHood/ShooterHood.java, src/main/java/org/team5924/frc2026/subsystems/pivots/shooterHood/ShooterHoodIO*
Removed left/right per-instance wiring and RobotState integration; introduced internal currentState and new MANUAL_ANGLE state; replaced @Setter fields with controlled setInput(DoubleSupplier) and setAutoInput(double) methods with clamping; updated IO logging to remove side prefix; unified TalonFX configuration and removed side-based tunable branching; changed constructor to no-arg.
HopperElevator Subsystem (New)
src/main/java/org/team5924/frc2026/subsystems/hopperElevator/HopperElevator.java, src/main/java/org/team5924/frc2026/subsystems/hopperElevator/HopperElevatorIO*
Added new subsystem managing elevator height via TalonFX/CANcoder; implements state machine (OFF, STOW, EXTENDED, MANUAL, MOVING); computes setpoint attainment with optional timeout gating; includes motor-disconnection and overheat alerts; added HopperElevatorIOTalonFX implementation with motion-magic control, tunable gains, and meter-based height conversion.
Turret Subsystem Removal
src/main/java/org/team5924/frc2026/subsystems/turret/Turret.java, src/main/java/org/team5924/frc2026/subsystems/turret/TurretIO*
Completely removed Turret subsystem (including TurretIO, TurretIOSim, TurretIOTalonFX) and all turret-related state tracking, goal/current state management, motor alerts, and APIs.
Roller Subsystem Updates
src/main/java/org/team5924/frc2026/subsystems/rollers/generic/GenericRollerIOTalonFX.java, src/main/java/org/team5924/frc2026/subsystems/rollers/hopper/Hopper.java, src/main/java/org/team5924/frc2026/subsystems/rollers/hopper/HopperIOTalonFX.java, src/main/java/org/team5924/frc2026/subsystems/rollers/indexer/Indexer.java, src/main/java/org/team5924/frc2026/subsystems/rollers/indexer/IndexerIOTalonFX.java, src/main/java/org/team5924/frc2026/subsystems/rollers/intake/Intake.java, src/main/java/org/team5924/frc2026/subsystems/rollers/intake/IntakeFollowerIO.java, src/main/java/org/team5924/frc2026/subsystems/rollers/intake/IntakeFollowerIOTalonFX.java, src/main/java/org/team5924/frc2026/subsystems/rollers/intake/IntakeIOTalonFX.java, src/main/java/org/team5924/frc2026/subsystems/rollers/intake/IntakeIOSim.java
Changed GenericRollerIOTalonFX.talon from private final to protected final; removed RobotState integration from Hopper/Indexer/Intake; added local currentState tracking in each; updated Hopper voltage default (4.0→6.0); updated Indexer voltage (4.0→8.0) and added handleCurrentState() override gated on flywheel setpoint; added new IntakeFollowerIO interface and IntakeFollowerIOTalonFX implementation for intake follower motor; removed redundant runVolts/stop overrides from Hopper/Indexer IO; added follower field to IntakeIOTalonFX.
IntakePivot State Management
src/main/java/org/team5924/frc2026/subsystems/pivots/intakePivot/IntakePivot.java, src/main/java/org/team5924/frc2026/subsystems/pivots/intakePivot/IntakePivotIOTalonFX.java
Removed RobotState dependency; introduced local currentState tracking; renamed motor-disconnect alert to motorDisconnected; updated periodic output and state transitions to use internal state; adjusted IntakePivotIOTalonFX tuning defaults (kD: 0.5→0.0, kS: 0.2→0.2, MotionCruiseVelocity: 10.0→100.0, MotionAcceleration: 100.0→1000.0).
Launch Utility Updates
src/main/java/org/team5924/frc2026/util/LaunchCalculator.java, src/main/java/org/team5924/frc2026/util/LauncherConstants.java
Removed turretRadians from LaunchingParameters record; removed preset instances (passingPreset, hubPreset, etc.); updated hood preset constants to use unified ShooterHood; refactored getParameters() signature from getParameters(boolean isLeft) to getParameters(); removed turret angle computation (getTurretAngle); updated pose sourcing to use getOdometryPose() instead of getEstimatedPose(); consolidated getDriveAngleWithLauncherOffset() parameters by removing left/right parameter; replaced robotToLauncherLeft/Right with single robotToLauncher transform.
Vision Calibration & Inputs
src/main/java/org/team5924/frc2026/subsystems/vision/VisionConstants.java, src/main/java/org/team5924/frc2026/subsystems/vision/VisionIO.java, src/main/java/org/team5924/frc2026/subsystems/vision/VisionIOPhotonVision.java
Updated FRONT_LEFT/RIGHT_TRANSFORM rotation parameters (changed pitch from ±55° to ∓55°, added ±8° roll); added new VisionIO.TranslationRotation record for camera-to-target orientation; added cameraToTarget field to VisionIOInputs; made robotToCamera tunable via LoggedTunableNumber calibration parameters (roll/pitch/yaw/x/y/z); updated VisionIOPhotonVision to decompose rotation and populate TranslationRotation.

Sequence Diagram

sequenceDiagram
    participant Driver
    participant DriveCommands as DriveCommands<br/>(Launching)
    participant LaunchCalculator
    participant RobotState
    participant Drive
    participant Flywheel
    participant ShooterHood

    Driver->>DriveCommands: Trigger joystickDriveWhileLaunching()
    DriveCommands->>LaunchCalculator: getParameters()
    LaunchCalculator->>RobotState: getOdometryPose()
    RobotState-->>LaunchCalculator: robotPose
    LaunchCalculator->>LaunchCalculator: Compute hood angle,<br/>flywheel speed,<br/>turret angle
    LaunchCalculator-->>DriveCommands: LaunchingParameters
    DriveCommands->>DriveCommands: Compute angular velocity<br/>using kP/kD gains<br/>and yaw error
    DriveCommands->>DriveCommands: Compute polar velocity<br/>constraints using<br/>lookahead
    DriveCommands->>Drive: runVelocity(vx, vy, omega)
    DriveCommands->>Flywheel: setAutoInput(speed)
    DriveCommands->>ShooterHood: setAutoInput(angle)
    Flywheel->>Flywheel: Execute AUTO state<br/>using speed target
    ShooterHood->>ShooterHood: Execute AUTO state<br/>using angle target
    DriveCommands->>DriveCommands: atLaunchGoal()?<br/>Check yaw tolerance
    DriveCommands-->>Driver: Ready to launch
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • Hmb all functionality #78: Major overlapping refactor consolidating left/right subsystems and updating LaunchCalculator, RobotState, and drivetrain wiring across the same core classes.
  • Implement Turret #56: Prior turret subsystem implementation that is now removed and replaced with HopperElevator; direct architectural conflict.
  • Flywheel tuning #81: Concurrent flywheel consolidation effort touching Constants, Flywheel subsystem, and RobotContainer wiring.

Suggested reviewers

  • arcadeArchitect
  • marisa07

Poem

🐰 Hops of joy for launcher dreams,
Where turrets fall and single beams,
Hood and wheel now unified,
Elevator hopping high with pride,
One shot true, the rabbit cries! 🎯

🚥 Pre-merge checks | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided by the author, making it impossible to assess whether it relates to the changeset. Add a detailed pull request description explaining the major changes: turret removal, shooter consolidation, hopper elevator addition, and related refactoring across subsystems.
Docstring Coverage ⚠️ Warning Docstring coverage is 4.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Hopper elevator' is vague and generic, using non-descriptive terms that don't convey meaningful information about the substantial changes in the changeset. Revise the title to be more specific and descriptive, e.g., 'Replace turret subsystem with hopper elevator' or 'Consolidate shooter to single instances and add hopper elevator'.

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

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

Copy link
Copy Markdown
Contributor

@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.

Actionable comments posted: 15

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/main/java/org/team5924/frc2026/util/LaunchCalculator.java (2)

335-357: ⚠️ Potential issue | 🟠 Major

The new zeroed chassis speed disables flight-time compensation.

robotVelocity is now always new ChassisSpeeds(), so the iterative lookahead never applies any offsetX / offsetY. Shots taken while the robot is moving will be aimed as if the launcher were stationary.

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

In `@src/main/java/org/team5924/frc2026/util/LaunchCalculator.java` around lines
335 - 357, The robotVelocity was incorrectly hardcoded to new ChassisSpeeds(),
which zeroes launcherVelocity and prevents flight-time compensation; restore the
real field-relative robot velocity (use
RobotState.getInstance().getFieldSetpointVelocity() or the prior method that
returns current chassis speeds), then compute launcherVelocity exactly as before
with DriverStation.isAutonomous() ? robotVelocity :
GeomUtil.transformVelocity(robotVelocity,
robotToLauncher.getTranslation().toTranslation2d(), robotAngle) so the iterative
lookahead (using launcherVelocity.vxMetersPerSecond / vyMetersPerSecond)
produces nonzero offsetX/offsetY when the robot is moving; also guard against
null/optional returns from RobotState.getInstance() if needed.

152-157: ⚠️ Potential issue | 🔴 Critical

Passing mode still dereferences empty lookup tables.

All passing*Map population is commented out above, but passing can still become true once the robot crosses hubCenter. At that point the passingTimeOfFlightMap, passingHoodAngleMap, and passingFlywheelSpeedMap lookups return null and this method will blow up.

Also applies to: 224-235, 308-347, 371-395

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

In `@src/main/java/org/team5924/frc2026/util/LaunchCalculator.java` around lines
152 - 157, The code can set passing=true when crossing hubCenter but all
passing*Map populations are commented out, causing NPEs when calling
passingTimeOfFlightMap/passingHoodAngleMap/passingFlywheelSpeedMap; fix by
guarding all lookups and assignments so they never dereference a null map entry:
in methods that use passing and the maps (e.g., the static init logic and the
calculation methods referenced by passing, hubCenter, passingTimeOfFlightMap,
passingHoodAngleMap, passingFlywheelSpeedMap, timeOfFlightMap, hoodAngleMap,
flywheelSpeedMap) add null-safe checks (map != null && map.containsKey(key) or
value != null) and if the passing maps are empty or missing fall back to the
non-passing maps or sensible defaults, or prevent toggling passing to true
unless the passing maps are populated; apply the same null-safe pattern to all
affected blocks (around the hubCenter transition and the lookup points noted).
src/main/java/org/team5924/frc2026/RobotContainer.java (1)

341-350: ⚠️ Potential issue | 🔴 Critical

Use onFalse(...) for the intake shutoff binding.

Both rightBumper() bindings currently use .onTrue(), causing both commands to fire when the button is pressed. The shutdown command (lines 341–350) then immediately cancels the intake startup command, leaving the intake stowed/off instead of running. Change the second binding to .onFalse() so intake activates on press and deactivates on release—matching the working pattern already used for leftBumper() (lines 373–382).

Suggested fix
 driveController
     .rightBumper()
-    .onTrue(
+    .onFalse(
         Commands.runOnce(
             () -> {
               intakePivot.setGoalState(IntakePivotState.STOW);
               intake.setGoalState(IntakeState.OFF);
             },
             intakePivot,
             intake));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/team5924/frc2026/RobotContainer.java` around lines 341 -
350, The second rightBumper binding currently uses .onTrue(), causing both
startup and shutdown commands to run on press; change that call to .onFalse() so
the lambda that sets intakePivot.setGoalState(IntakePivotState.STOW) and
intake.setGoalState(IntakeState.OFF) runs on button release instead of
press—follow the same pattern as the leftBumper() binding; update the
driveController.rightBumper().onTrue(...) invocation to
driveController.rightBumper().onFalse(...) for the intake shutdown command that
references intakePivot and intake.
🧹 Nitpick comments (7)
.vscode/settings.json (1)

65-65: Consider avoiding hard-pinning -Xmx4G in repo-shared workspace settings.

This can be heavy on lower-memory dev machines. If this is only needed for some contributors, consider documenting it in README (or moving to user settings) and keeping a lower default here.

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

In @.vscode/settings.json at line 65, The workspace setting "java.jdt.ls.vmargs"
currently hard-pins "-Xmx4G", which can be too large for low-memory machines;
remove or lower that flag in .vscode/settings.json (e.g., drop the -Xmx4G or
replace it with a safer default like -Xmx1G), and instead document the
recommended JVM args in the README or instruct contributors to add the higher
-Xmx value in their personal VS Code user settings if they need it; update the
README note to include the exact flag string and rationale so maintainers can
opt into the larger heap locally rather than forcing it in the repo-shared
"java.jdt.ls.vmargs".
src/main/java/org/team5924/frc2026/subsystems/vision/VisionIO.java (1)

42-44: Consider adding Javadoc for the TranslationRotation record.

The rotation units (degrees vs radians) are not documented. Based on usage in VisionIOPhotonVision, these are degrees, but a brief Javadoc comment would clarify this for future maintainers.

📝 Suggested documentation
+  /** Represents translation and rotation (roll, pitch, yaw in degrees). */
   public static record TranslationRotation(
       Translation3d translation, double roll, double pitch, double yaw) {}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/team5924/frc2026/subsystems/vision/VisionIO.java` around
lines 42 - 44, Add Javadoc to the TranslationRotation record to document its
purpose and explicitly state that roll, pitch, and yaw are in degrees (as used
in VisionIOPhotonVision); update the comment above the record
TranslationRotation to describe the translation field (Translation3d) and each
rotation component (roll, pitch, yaw) with units and any conventions (e.g., axis
order or right-hand rule) so future maintainers know how VisionIOPhotonVision
expects and produces these values.
src/main/java/org/team5924/frc2026/subsystems/vision/VisionIOPhotonVision.java (1)

54-54: Remove commented-out code.

The line // this.robotToCamera = robotToCamera; is dead code and should be removed to keep the codebase clean.

🧹 Proposed fix
   public VisionIOPhotonVision(String name, Transform3d robotToCamera) {
     camera = new PhotonCamera(name);
-    // this.robotToCamera = robotToCamera;

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

In
`@src/main/java/org/team5924/frc2026/subsystems/vision/VisionIOPhotonVision.java`
at line 54, Remove the dead commented-out assignment in VisionIOPhotonVision by
deleting the line "// this.robotToCamera = robotToCamera;" in the class (remove
any leftover commented assignment referencing robotToCamera) so the codebase has
no commented-out, unused lines; ensure no other references rely on that
commented line before removing.
src/main/java/org/team5924/frc2026/subsystems/rollers/intake/IntakeIOSim.java (1)

28-30: Remove or replace commented-out stub with a TODO.

Commented-out code adds clutter. If follower simulation support is planned, use a TODO comment to track the work instead.

🧹 Option 1: Remove commented code
   public IntakeIOSim() {
     super(
         DCMotor.getKrakenX60Foc(1), Constants.Intake.SIM_MOI, Constants.Intake.MOTOR_TO_MECHANISM);
   }
-
-  // `@Override`
-  // public void updateFollowerInputs() {}
 }
📝 Option 2: Replace with TODO
   public IntakeIOSim() {
     super(
         DCMotor.getKrakenX60Foc(1), Constants.Intake.SIM_MOI, Constants.Intake.MOTOR_TO_MECHANISM);
   }
-
-  // `@Override`
-  // public void updateFollowerInputs() {}
+
+  // TODO: Implement updateFollowerInputs() for follower motor simulation
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/org/team5924/frc2026/subsystems/rollers/intake/IntakeIOSim.java`
around lines 28 - 30, The commented-out stub for updateFollowerInputs in
IntakeIOSim should be removed or replaced with a clear TODO; locate the
IntakeIOSim class and either delete the commented lines "// `@Override` // public
void updateFollowerInputs() {}" to reduce clutter, or replace them with a
single-line TODO comment referencing the method name (e.g., "TODO: implement
updateFollowerInputs simulation/follower support") so the intent is tracked
without leaving commented code; ensure formatting and spacing follow existing
file style.
src/main/java/org/team5924/frc2026/subsystems/rollers/intake/Intake.java (1)

45-48: Remove empty periodic() override.

This override only delegates to super.periodic() without adding any logic. It can be safely removed as the parent class method will be called automatically.

🧹 Proposed cleanup
-  `@Override`
-  public void periodic() {
-    super.periodic();
-  }
-
   public void setGoalState(IntakeState goalState) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/team5924/frc2026/subsystems/rollers/intake/Intake.java`
around lines 45 - 48, The Intake class contains an empty periodic() override
that only calls super.periodic(); remove the override method from Intake (delete
the periodic() method in class Intake) so the parent class's periodic() runs
without a redundant override.
src/main/java/org/team5924/frc2026/subsystems/flywheel/FlywheelIOSim.java (1)

52-55: Hardcoded loop bound assumes 4-motor array size.

The loop iterates exactly 4 times to populate motorConnected and tempCelsius arrays. If the array size in FlywheelIOInputs is changed, this will cause an ArrayIndexOutOfBoundsException.

Consider using the array length directly:

♻️ Proposed fix
-    for (int i = 0; i < 4; ++i) {
+    for (int i = 0; i < inputs.motorConnected.length; ++i) {
       inputs.motorConnected[i] = true;
       inputs.tempCelsius[i] = 25.0;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/team5924/frc2026/subsystems/flywheel/FlywheelIOSim.java`
around lines 52 - 55, The loop in FlywheelIOSim hardcodes 4 iterations causing
potential ArrayIndexOutOfBoundsException if FlywheelIOInputs arrays change;
update the loop to iterate using the arrays' actual length (e.g., use
inputs.motorConnected.length or inputs.tempCelsius.length) so both
inputs.motorConnected and inputs.tempCelsius are populated safely for whatever
size those arrays currently have.
src/main/java/org/team5924/frc2026/subsystems/rollers/intake/IntakeIOTalonFX.java (1)

23-28: Follower field is stored but never used after initialization.

The follower instance is created (which configures the TalonFX in follower mode via its constructor), but the field is never accessed afterward. This works because CTRE follower mode operates independently after setControl(new Follower(...)) is called.

However, the follower motor's telemetry (temperature, current, connection status) is never captured since follower.updateInputs() is never called. Consider whether follower diagnostics should be logged for monitoring motor health.

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

In
`@src/main/java/org/team5924/frc2026/subsystems/rollers/intake/IntakeIOTalonFX.java`
around lines 23 - 28, The follower instance (follower of type
IntakeFollowerIOTalonFX) is constructed but never used, so its telemetry
(temperature/current/connection) is never collected; either remove the field if
you intentionally don’t monitor it or call its update method from the primary
subsystem telemetry path—specifically, add a call to follower.updateInputs()
inside IntakeIOTalonFX.updateInputs() (or whatever input-polling method is used)
and forward the follower’s telemetry into your existing input/telemetry
structure so the follower motor health is logged; if opting to remove, delete
the follower field and constructor instantiation instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/org/team5924/frc2026/commands/drive/DriveCommands.java`:
- Around line 261-274: The early return when driveLauncherCORMaxErrorDeg.get() <
driveLauncherCORMinErrorDeg.get() causes no new chassis command or setpoint
velocity to be published; instead remove the return and treat the
tunables-as-invalid case by setting a safe corScalar (e.g., 1.0) and continue to
compute/apply the chassis speeds and update RobotState.robotSetpointVelocity so
the drivetrain output and RobotState remain in sync; modify the block around
driveLauncherCORMaxErrorDeg/driveLauncherCORMinErrorDeg and the corScalar
calculation in DriveCommands (the code using parameters.driveAngle(),
RobotState.getInstance().getRotation(), and corScalar) to ensure a fallback path
publishes the chassis command and updates RobotState rather than returning
early.

In `@src/main/java/org/team5924/frc2026/Robot.java`:
- Around line 129-133: The low battery alert reset currently in robotInit()
checks DriverStation.isEnabled(), which is false at startup, so move the
disabledTimer.reset() and lowBatteryAlert.set(false) logic out of robotInit()
into the enabled-mode init methods (e.g., teleopInit() and autonomousInit()) so
the timer and alert are correctly reset when the robot transitions to enabled;
update references to disabledTimer and lowBatteryAlert in those methods and
remove the ineffective check from robotInit().

In `@src/main/java/org/team5924/frc2026/RobotContainer.java`:
- Around line 73-87: Add a HopperElevator field and a realHopperElevator boolean
to RobotContainer and instantiate it in all three init branches (REAL, SIM,
default) following the same pattern used for other subsystems (e.g., hopper,
intake): declare private final HopperElevator hopperElevator; add private final
boolean realHopperElevator; set realHopperElevator based on the environment like
the other realX flags, and in each branch (REAL, SIM, default) assign
hopperElevator to the platform-specific implementation (or a simulation stub)
consistent with how hopper and intake are constructed so its periodic() will be
scheduled.
- Around line 384-392: Replace the two separate commands with a single
continuous default command on shooterHood: remove the Commands.runOnce(...)
default and the driveController.rightStick().onTrue(...) binding, and instead
call shooterHood.setDefaultCommand(Commands.run( () -> {
shooterHood.setGoalState(ShooterHood.ShooterHoodState.MANUAL);
shooterHood.setInput(() -> driveController.getRightY()); }, shooterHood )); so
the MANUAL goal is set and the input supplier is refreshed every cycle (this
mirrors the patterns used in ManualShooterCommands and IntakePivotCommands and
prevents handleManualState() from reading a stale input).

In `@src/main/java/org/team5924/frc2026/subsystems/flywheel/Flywheel.java`:
- Around line 145-160: The flag being published is too generic — change the
logic in handleCurrentState/isAtSetpoint so
RobotState.setFlywheelAtSetpoint(...) only becomes true when the flywheel is
both in a feedable mode (whitelist the feedable enums, e.g., FlywheelState.AUTO
and FlywheelState.MANUAL_SETPOINT) and the measured velocity matches the
intended target; to do that, compute the target by calling
getTargetVelocityRotationsPerSec() (ensure autoInput is refreshed before
comparison), then call EqualsUtil.epsilonEquals(...) and only set
RobotState.setFlywheelAtSetpoint(isReady) when goalState is one of the allowed
feedable states (do not set it for OFF or open-loop/idle states); apply the same
whitelist-based check to the other identical location around the later block
(lines ~169-171) that currently publishes the generic setpoint flag.

In
`@src/main/java/org/team5924/frc2026/subsystems/hopperElevator/HopperElevator.java`:
- Around line 123-134: The code allows HopperElevatorState.MOVING to be accepted
and even sets this.goalState and currentState before rejecting it; change
setGoalState to validate and reject MOVING before mutating any fields (i.e., if
goalState == HopperElevatorState.MOVING, log/report error and return
immediately), avoid fall-through in the switch, and only set this.goalState and
currentState when a legitimate state change is accepted; also ensure
lastStateChange is updated whenever you actually change currentState/goalState
so timeout tracking measures real transitions (refer to setGoalState,
this.goalState, currentState, lastStateChange, and HopperElevatorState.MOVING).
- Around line 89-95: The isAtSetpoint() method is comparing
inputs.setpointMeters to inputs.positionRads using
Constants.HopperElevator.EPSILON_RADS, which mixes linear and angular units;
change the comparison so both sides use the same units (either compare a
positionMeters field to setpointMeters using an EPSILON_METERS tolerance, or
convert setpointMeters to radians and compare to inputs.positionRads using
EPSILON_RADS). Update the referenced symbols (inputs.setpointMeters,
inputs.positionRads, Constants.HopperElevator.EPSILON_RADS and/or add
Constants.HopperElevator.EPSILON_METERS) and keep the existing timeout check
(ENABLE_TIMEOUT / timeSinceLastStateChange / STATE_TIMEOUT) unchanged.
- Around line 97-121: The code never drives the elevator from joystick input
because MANUAL ends up treated like MOVING (using goalState.getHeightMeters())
and handleManualState() only stops on deadzone without commanding motion; update
handleCurrentState / the MOVING branch to detect when goalState ==
HopperElevatorState.MANUAL and delegate to manual handling (call
handleManualState or inline manual logic) instead of calling
io.setHeight(goalState.getHeightMeters()), and change handleManualState() to
actively command the actuator when outside the deadzone (use the live input
value scaled to the appropriate output method on io — e.g., percent/voltage
setter or a max-volts tunable — rather than using the ManualVolts tunable), and
apply the same fix in the other similar block mentioned (lines 123-134) so
manual input actually drives the mechanism.
- Around line 53-56: STOW and EXTENDED enum presets are both initialized to 0.0
via LoggedTunableNumber, so set realistic non-zero defaults: update the enum
entry for STOW(new LoggedTunableNumber("HopperElevator/StowHeightMeters", X))
and EXTENDED(new LoggedTunableNumber("HopperElevator/ExtendedHeightMeters", Y))
to meaningful heights (replace X and Y with measured default stow and extended
heights in meters), leaving the NetworkTables keys unchanged; no other logic
changes needed (leave MANUAL and MOVING as-is).

In
`@src/main/java/org/team5924/frc2026/subsystems/hopperElevator/HopperElevatorIOTalonFX.java`:
- Around line 64-69: The dashboard tunable keys and alert labels in
HopperElevatorIOTalonFX still use IntakePivot/ShooterHood names; rename the
LoggedTunableNumber keys (e.g., motionCruiseVelocity, motionAcceleration,
motionJerk) to use a unique prefix like "HopperElevator/..." and update any
alert creation/update calls that reference "ShooterHood" or "IntakePivot" (the
init/update alerts further down in this class) so they use "HopperElevator" (or
another hopper-specific name) to avoid colliding with other subsystems; ensure
you update all similar tunables and alert strings in this file (the blocks
around the other tunable definitions and the init/update alert code) to the new
prefix.
- Around line 98-106: The gravity type for the elevator is set incorrectly to
Arm_Cosine which makes kG vary with angle; change the GravityType assignment on
the Slot0Configs instance (slot0Configs.GravityType) from
GravityTypeValue.Arm_Cosine to GravityTypeValue.Elevator_Static so the kG
feedforward remains constant for the linear elevator (update the assignment
where slot0Configs is configured in HopperElevatorIOTalonFX).
- Around line 168-172: The current startup code in HopperElevatorIOTalonFX calls
BaseStatusSignal.waitForAll(0.5, cancoderAbsolutePosition) but then
unconditionally calls cancoder.setPosition(0.0) and talon.setPosition(0.0),
discarding the absolute reading; instead, use the cancoderAbsolutePosition value
to initialize the Talon sensor or only zero when you have a physical reference:
read the absolute encoder value from cancoderAbsolutePosition after waitForAll
and convert it into the Talon sensor units (use the existing conversion logic
used elsewhere) and call talon.setPosition(convertedValue); only call
cancoder.setPosition(0.0) / talon.setPosition(0.0) unconditionally if a verified
homing condition exists (e.g., an atStowed limit switch or the value lies within
an expected deadband), otherwise preserve the absolute reading so subsequent
moves aren’t offset.

In `@src/main/java/org/team5924/frc2026/subsystems/vision/VisionIO.java`:
- Line 27: Remove the stray debug field or give it a meaningful name: locate the
public boolean field declared as "public boolean a = true;" in the VisionIO
class and either delete it if unused, or rename it to a descriptive identifier
(e.g., isEnabled, debugMode, or useVisionProcessing) and update all references
within VisionIO accordingly so intent is clear and no single-letter field
remains.

In `@src/main/java/org/team5924/frc2026/util/LauncherConstants.java`:
- Around line 26-30: The field robotToLauncher in class LauncherConstants is
intended as a constant but is missing the final modifier; update the declaration
of robotToLauncher (public static Transform3d robotToLauncher) to be public
static final Transform3d robotToLauncher so the Transform3d instance cannot be
reassigned at runtime, leaving the existing initializer (new Transform3d(...))
unchanged.

---

Outside diff comments:
In `@src/main/java/org/team5924/frc2026/RobotContainer.java`:
- Around line 341-350: The second rightBumper binding currently uses .onTrue(),
causing both startup and shutdown commands to run on press; change that call to
.onFalse() so the lambda that sets
intakePivot.setGoalState(IntakePivotState.STOW) and
intake.setGoalState(IntakeState.OFF) runs on button release instead of
press—follow the same pattern as the leftBumper() binding; update the
driveController.rightBumper().onTrue(...) invocation to
driveController.rightBumper().onFalse(...) for the intake shutdown command that
references intakePivot and intake.

In `@src/main/java/org/team5924/frc2026/util/LaunchCalculator.java`:
- Around line 335-357: The robotVelocity was incorrectly hardcoded to new
ChassisSpeeds(), which zeroes launcherVelocity and prevents flight-time
compensation; restore the real field-relative robot velocity (use
RobotState.getInstance().getFieldSetpointVelocity() or the prior method that
returns current chassis speeds), then compute launcherVelocity exactly as before
with DriverStation.isAutonomous() ? robotVelocity :
GeomUtil.transformVelocity(robotVelocity,
robotToLauncher.getTranslation().toTranslation2d(), robotAngle) so the iterative
lookahead (using launcherVelocity.vxMetersPerSecond / vyMetersPerSecond)
produces nonzero offsetX/offsetY when the robot is moving; also guard against
null/optional returns from RobotState.getInstance() if needed.
- Around line 152-157: The code can set passing=true when crossing hubCenter but
all passing*Map populations are commented out, causing NPEs when calling
passingTimeOfFlightMap/passingHoodAngleMap/passingFlywheelSpeedMap; fix by
guarding all lookups and assignments so they never dereference a null map entry:
in methods that use passing and the maps (e.g., the static init logic and the
calculation methods referenced by passing, hubCenter, passingTimeOfFlightMap,
passingHoodAngleMap, passingFlywheelSpeedMap, timeOfFlightMap, hoodAngleMap,
flywheelSpeedMap) add null-safe checks (map != null && map.containsKey(key) or
value != null) and if the passing maps are empty or missing fall back to the
non-passing maps or sensible defaults, or prevent toggling passing to true
unless the passing maps are populated; apply the same null-safe pattern to all
affected blocks (around the hubCenter transition and the lookup points noted).

---

Nitpick comments:
In @.vscode/settings.json:
- Line 65: The workspace setting "java.jdt.ls.vmargs" currently hard-pins
"-Xmx4G", which can be too large for low-memory machines; remove or lower that
flag in .vscode/settings.json (e.g., drop the -Xmx4G or replace it with a safer
default like -Xmx1G), and instead document the recommended JVM args in the
README or instruct contributors to add the higher -Xmx value in their personal
VS Code user settings if they need it; update the README note to include the
exact flag string and rationale so maintainers can opt into the larger heap
locally rather than forcing it in the repo-shared "java.jdt.ls.vmargs".

In `@src/main/java/org/team5924/frc2026/subsystems/flywheel/FlywheelIOSim.java`:
- Around line 52-55: The loop in FlywheelIOSim hardcodes 4 iterations causing
potential ArrayIndexOutOfBoundsException if FlywheelIOInputs arrays change;
update the loop to iterate using the arrays' actual length (e.g., use
inputs.motorConnected.length or inputs.tempCelsius.length) so both
inputs.motorConnected and inputs.tempCelsius are populated safely for whatever
size those arrays currently have.

In `@src/main/java/org/team5924/frc2026/subsystems/rollers/intake/Intake.java`:
- Around line 45-48: The Intake class contains an empty periodic() override that
only calls super.periodic(); remove the override method from Intake (delete the
periodic() method in class Intake) so the parent class's periodic() runs without
a redundant override.

In
`@src/main/java/org/team5924/frc2026/subsystems/rollers/intake/IntakeIOSim.java`:
- Around line 28-30: The commented-out stub for updateFollowerInputs in
IntakeIOSim should be removed or replaced with a clear TODO; locate the
IntakeIOSim class and either delete the commented lines "// `@Override` // public
void updateFollowerInputs() {}" to reduce clutter, or replace them with a
single-line TODO comment referencing the method name (e.g., "TODO: implement
updateFollowerInputs simulation/follower support") so the intent is tracked
without leaving commented code; ensure formatting and spacing follow existing
file style.

In
`@src/main/java/org/team5924/frc2026/subsystems/rollers/intake/IntakeIOTalonFX.java`:
- Around line 23-28: The follower instance (follower of type
IntakeFollowerIOTalonFX) is constructed but never used, so its telemetry
(temperature/current/connection) is never collected; either remove the field if
you intentionally don’t monitor it or call its update method from the primary
subsystem telemetry path—specifically, add a call to follower.updateInputs()
inside IntakeIOTalonFX.updateInputs() (or whatever input-polling method is used)
and forward the follower’s telemetry into your existing input/telemetry
structure so the follower motor health is logged; if opting to remove, delete
the follower field and constructor instantiation instead.

In `@src/main/java/org/team5924/frc2026/subsystems/vision/VisionIO.java`:
- Around line 42-44: Add Javadoc to the TranslationRotation record to document
its purpose and explicitly state that roll, pitch, and yaw are in degrees (as
used in VisionIOPhotonVision); update the comment above the record
TranslationRotation to describe the translation field (Translation3d) and each
rotation component (roll, pitch, yaw) with units and any conventions (e.g., axis
order or right-hand rule) so future maintainers know how VisionIOPhotonVision
expects and produces these values.

In
`@src/main/java/org/team5924/frc2026/subsystems/vision/VisionIOPhotonVision.java`:
- Line 54: Remove the dead commented-out assignment in VisionIOPhotonVision by
deleting the line "// this.robotToCamera = robotToCamera;" in the class (remove
any leftover commented assignment referencing robotToCamera) so the codebase has
no commented-out, unused lines; ensure no other references rely on that
commented line before removing.
🪄 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: 81108b4f-ea27-420c-a5c7-cebf98b2ab92

📥 Commits

Reviewing files that changed from the base of the PR and between e029dee and 5b7d73f.

📒 Files selected for processing (40)
  • .vscode/settings.json
  • src/main/java/org/team5924/frc2026/Constants.java
  • src/main/java/org/team5924/frc2026/Robot.java
  • src/main/java/org/team5924/frc2026/RobotContainer.java
  • src/main/java/org/team5924/frc2026/RobotState.java
  • src/main/java/org/team5924/frc2026/commands/AutoBuilder.java
  • src/main/java/org/team5924/frc2026/commands/drive/DriveCommands.java
  • src/main/java/org/team5924/frc2026/commands/drive/DriveToPose.java
  • src/main/java/org/team5924/frc2026/commands/shooter/AutoScoreCommands.java
  • src/main/java/org/team5924/frc2026/commands/shooter/ManualShooterCommands.java
  • src/main/java/org/team5924/frc2026/subsystems/flywheel/Flywheel.java
  • src/main/java/org/team5924/frc2026/subsystems/flywheel/FlywheelIO.java
  • src/main/java/org/team5924/frc2026/subsystems/flywheel/FlywheelIOSim.java
  • src/main/java/org/team5924/frc2026/subsystems/flywheel/FlywheelIOTalonFX.java
  • src/main/java/org/team5924/frc2026/subsystems/hopperElevator/HopperElevator.java
  • src/main/java/org/team5924/frc2026/subsystems/hopperElevator/HopperElevatorIO.java
  • src/main/java/org/team5924/frc2026/subsystems/hopperElevator/HopperElevatorIOTalonFX.java
  • src/main/java/org/team5924/frc2026/subsystems/pivots/intakePivot/IntakePivot.java
  • src/main/java/org/team5924/frc2026/subsystems/pivots/intakePivot/IntakePivotIOTalonFX.java
  • src/main/java/org/team5924/frc2026/subsystems/pivots/shooterHood/ShooterHood.java
  • src/main/java/org/team5924/frc2026/subsystems/pivots/shooterHood/ShooterHoodIOSim.java
  • src/main/java/org/team5924/frc2026/subsystems/pivots/shooterHood/ShooterHoodIOTalonFX.java
  • src/main/java/org/team5924/frc2026/subsystems/rollers/generic/GenericRollerIOTalonFX.java
  • src/main/java/org/team5924/frc2026/subsystems/rollers/hopper/Hopper.java
  • src/main/java/org/team5924/frc2026/subsystems/rollers/hopper/HopperIOTalonFX.java
  • src/main/java/org/team5924/frc2026/subsystems/rollers/indexer/Indexer.java
  • src/main/java/org/team5924/frc2026/subsystems/rollers/indexer/IndexerIOTalonFX.java
  • src/main/java/org/team5924/frc2026/subsystems/rollers/intake/Intake.java
  • src/main/java/org/team5924/frc2026/subsystems/rollers/intake/IntakeFollowerIO.java
  • src/main/java/org/team5924/frc2026/subsystems/rollers/intake/IntakeFollowerIOTalonFX.java
  • src/main/java/org/team5924/frc2026/subsystems/rollers/intake/IntakeIOSim.java
  • src/main/java/org/team5924/frc2026/subsystems/rollers/intake/IntakeIOTalonFX.java
  • src/main/java/org/team5924/frc2026/subsystems/turret/Turret.java
  • src/main/java/org/team5924/frc2026/subsystems/turret/TurretIOSim.java
  • src/main/java/org/team5924/frc2026/subsystems/turret/TurretIOTalonFX.java
  • src/main/java/org/team5924/frc2026/subsystems/vision/VisionConstants.java
  • src/main/java/org/team5924/frc2026/subsystems/vision/VisionIO.java
  • src/main/java/org/team5924/frc2026/subsystems/vision/VisionIOPhotonVision.java
  • src/main/java/org/team5924/frc2026/util/LaunchCalculator.java
  • src/main/java/org/team5924/frc2026/util/LauncherConstants.java
💤 Files with no reviewable changes (5)
  • src/main/java/org/team5924/frc2026/subsystems/rollers/hopper/HopperIOTalonFX.java
  • src/main/java/org/team5924/frc2026/subsystems/rollers/indexer/IndexerIOTalonFX.java
  • src/main/java/org/team5924/frc2026/subsystems/turret/TurretIOTalonFX.java
  • src/main/java/org/team5924/frc2026/subsystems/turret/Turret.java
  • src/main/java/org/team5924/frc2026/subsystems/turret/TurretIOSim.java

Comment thread src/main/java/org/team5924/frc2026/Constants.java
Comment thread src/main/java/org/team5924/frc2026/Robot.java
Comment on lines 73 to +87
public class RobotContainer {
// Subsystems
private final Drive drive;
private SwerveDriveSimulation driveSimulation = null;
private Vision vision;

private final Vision vision;

private final Intake intake;
private final IntakePivot intakePivot;
private final Hopper hopper;
private final Indexer indexer;

private final ShooterHood shooterHoodRight;
private final Flywheel flywheelRight;
private final Turret turretRight;
private final ShooterHood shooterHood;
private final Flywheel flywheel;

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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, find the RobotContainer file and check its full contents
find . -name "RobotContainer.java" -type f

Repository: Team5924/GoldenGateRobotics2026

Length of output: 131


🏁 Script executed:

# Also look for HopperElevator in the codebase
rg -l "HopperElevator" --type java

Repository: Team5924/GoldenGateRobotics2026

Length of output: 378


🏁 Script executed:

# Read the full RobotContainer.java file to check for HopperElevator construction
wc -l ./src/main/java/org/team5924/frc2026/RobotContainer.java

Repository: Team5924/GoldenGateRobotics2026

Length of output: 135


🏁 Script executed:

# Read the full RobotContainer file
cat -n ./src/main/java/org/team5924/frc2026/RobotContainer.java

Repository: Team5924/GoldenGateRobotics2026

Length of output: 19793


🏁 Script executed:

# Search for HopperElevator instantiation (new HopperElevator)
rg "new HopperElevator" --type java -B 2 -A 2

Repository: Team5924/GoldenGateRobotics2026

Length of output: 708


🏁 Script executed:

# Check if there are any other Robot container-like classes or factories that might instantiate HopperElevator
rg "HopperElevator" --type java -B 2 -A 2

Repository: Team5924/GoldenGateRobotics2026

Length of output: 19426


Add HopperElevator to the composition root.

HopperElevator is not instantiated anywhere in the codebase. Without construction in RobotContainer, the subsystem's periodic() method never executes and the implementation becomes dead code. Add a HopperElevator field, a corresponding realHopperElevator flag, and instantiate it in all three initialization branches (REAL, SIM, and default) following the same pattern as other subsystems.

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

In `@src/main/java/org/team5924/frc2026/RobotContainer.java` around lines 73 - 87,
Add a HopperElevator field and a realHopperElevator boolean to RobotContainer
and instantiate it in all three init branches (REAL, SIM, default) following the
same pattern used for other subsystems (e.g., hopper, intake): declare private
final HopperElevator hopperElevator; add private final boolean
realHopperElevator; set realHopperElevator based on the environment like the
other realX flags, and in each branch (REAL, SIM, default) assign hopperElevator
to the platform-specific implementation (or a simulation stub) consistent with
how hopper and intake are constructed so its periodic() will be scheduled.

Comment thread src/main/java/org/team5924/frc2026/RobotContainer.java
@AutoLog
public static class VisionIOInputs {
public boolean connected = false;
public boolean a = true;
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

Remove or rename the debug field a.

The field public boolean a = true; has an unclear single-letter name and appears to be leftover debug or placeholder code. If this field is needed, give it a meaningful name that describes its purpose. If it's not needed, remove it before merging.

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

In `@src/main/java/org/team5924/frc2026/subsystems/vision/VisionIO.java` at line
27, Remove the stray debug field or give it a meaningful name: locate the public
boolean field declared as "public boolean a = true;" in the VisionIO class and
either delete it if unused, or rename it to a descriptive identifier (e.g.,
isEnabled, debugMode, or useVisionProcessing) and update all references within
VisionIO accordingly so intent is clear and no single-letter field remains.

Comment thread src/main/java/org/team5924/frc2026/util/LauncherConstants.java
@maiKuneho maiKuneho closed this Mar 28, 2026
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