WHERE Clause Compare VarChar(n) Column = VarChar(MAX) Variable Results in Inequality Comparison and Poor Query Performance
The Problems
You have two things working against you:

Local variables often have weird side effects
MAX datatypes can't be pushed, so you end up with late filters in your query plans

Some further reading:

Yet Another Post About Local Variables
MAX Data Types Do WHAT?
Why You Shouldn’t Ignore Filter Operators In Query Plans Part 1 | Part 2
Why does SQL Server use a better execution plan when I inline the variable?

In Particular
In your worse plan, there are two filter operators:

Each one is there to deal with the MAX type on @ProgramId. The length of the parameter doesn't matter much until you hit the max type, so long as it's the correct type, e.g. varchar = varchar or nvarchar = nvarchar
You may also see GetRangeThroughMismatchedType or GetRangeThroughConvertthere to deal with a date \ datetime mismatch:

Cast to date is sargable but is it a good idea?

You may find some overall relief by adding a recompile hint, but it won't fix the issue you're having around the MAX variable.