Skip to content

fix(core): refuse an explicit required arity with a default value - #164

Merged
carldebilly merged 1 commit into
mainfrom
dev/cdb/option-schema-followups
Nov 3, 2026
Merged

carldebilly merged 1 commit into
mainfrom
dev/cdb/option-schema-followups

Conversation

@carldebilly

Copy link
Copy Markdown
Member

Closes #66.

Six low-severity follow-ups from the PR #63 review panel, deferred past 0.11. Before changing anything, I checked each one against the current main:

# Item Status on main Here
1 Explicit OneOrMore/ExactlyOne with a C# default applies: the default never applies, with no signal Map refuses it (breaking)
2 Equal-duplicate enum values applies, narrowly exemption dropped; one message for every repeat
3 Service resolution before the lower-bound check now intended, documented in docs/commands.md no change
4 CaseSensitivity ?? global inlined applies: 14 sites, up from 4 EffectiveCaseSensitivity(global)
5 ResolveParameterArity pass-through applies inlined
6 CanConsumePositional identical branches partly fixed: the parameter version was removed, the property twin remained inlined

Breaking: explicit required arity with a default value

The binder enforces an explicit ExactlyOne or OneOrMore before it would fall back to the parameter's default, so that default could never apply. Map now throws, naming the parameter and the optional arity to use instead, for example:

Parameter 'channel' declares Arity ExactlyOne together with a default value, which can never apply because that
arity requires a value. Remove the default value, or use ReplArity.ZeroOrOne if the option may be left out.
  • Migration: docs/parameter-system.md carries a "Changed in 0.12" note.
  • Options groups: a group property's initializer has the same problem, but Map cannot detect it because PropertyInfo does not expose an initializer. The docs and ReplOptionAttribute.Arity say so.

Repeated scalar enum

Under an explicit ZeroOrMore, the message depended on how the repeat was spelled, not on the value. I measured both versions with --syllable Ga followed by a second entry:

Second entry Before After
--syllable Ga, --ga (flag alias) does not support repeated occurrences accepts a single enum value per invocation
--syllable ga, --syllable 1, --syllable Bu received multiple enum values accepts a single enum value per invocation

All of these already exited with code 2; only the message changes. A repeat that names the same value stays refused, as for every other scalar.

Test plan

  • Red before the fix, with a successful build: the three rows of When_AnExplicitLowerBoundArityHasADefaultValue_Then_MapFails, and the same-value row of the repeated-enum test.
  • Assertions: the tests pin the parameter name and the suggested arity. A ZeroOrOne option with a default value guards the side the refusal must not reach.
  • Existing tests: the ExactlyOne absence test drops its = null and keeps what it guards. The case-parity enum test becomes a row of the repeated-enum test.
  • ABI: removed or changed members are all private, and the two records only gain a method. No friend assembly calls them (Repl.Remote.Defaults uses HandlerArgumentBinder.TryGetCollectionElementType, unchanged).
  • Results:
    • Full suite: 2619 tests, 0 failed (13 skipped).
    • Release build: 0 warnings.
    • markdownlint: clean.

Follow-ups from the PR #63 review panel, deferred from 0.11:

- An explicit Arity of ExactlyOne or OneOrMore requires a value, and the
  binder enforces it before it would fall back to the parameter's
  default, so that default could never apply. Map now refuses the
  combination on a handler parameter, naming the parameter and the
  optional arity to use instead (ZeroOrOne for ExactlyOne, ZeroOrMore for
  OneOrMore). This is a breaking change for an app that declares both;
  docs/parameter-system.md carries a "Changed in 0.12" note. An
  options-group property's initializer has the same problem but cannot be
  detected, which the docs and ReplOptionAttribute.Arity now say.
- A scalar enum option repeated with the same value under an explicit
  ZeroOrMore arity passed the enum conflict check, which exempted equal
  duplicates, and then failed binding with "does not support repeated
  occurrences". Whether a repeat used the same spelling, the enum flag
  alias, another casing or the numeric value, the message depended on the
  spelling rather than the value. The exemption is gone, and every repeat
  of a scalar enum now reads "accepts a single enum value per
  invocation". That also removes the case comparison the check needed,
  and the global case sensitivity it took.
- "CaseSensitivity ?? global" was written out at fourteen sites, three of
  them behind a conditional. It is now EffectiveCaseSensitivity(global) on
  OptionSchemaEntry and OptionSchemaParameter.
- InvocationOptionParser.ResolveParameterArity, a pass-through to
  OptionSchema.ResolveParameterArity, is inlined at its one caller.
- CanConsumePositionalForProperty had two identical branches and is
  inlined as the comparison it was.

The third item of the issue, DI resolution ahead of an explicit lower
bound, is now the documented order (docs/commands.md) and is left as is.

TDD: the arity test (an option with OneOrMore, one with ExactlyOne, an
argument with OneOrMore) and the equal-duplicate enum row were red before
the fix: no exception on Map, and "does not support repeated occurrences".
They now also pin the parameter name and the suggested arity. A ZeroOrOne
option with a default value guards the side the refusal must not reach.
The existing ExactlyOne absence test declared "= null" on a nullable
parameter; it drops the default and keeps what it guards. The case-parity
enum test becomes the casing row of the repeated-enum test.

Closes #66
@carldebilly carldebilly added this to the 0.12.0 milestone Nov 3, 2026
@carldebilly

Copy link
Copy Markdown
Member Author

@codex review

@carldebilly

Copy link
Copy Markdown
Member Author

@autocarl please review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-03T04:33:42.748944Z 4cde862 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: 4cde86288d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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

Reviewed exact head 4cde862 and integration with current target d65f6eb. No concrete introduced P0-P2 findings.

Validation:

  • Release build of src/Repl.slnx: 0 warnings / 0 errors. Six repository test suites on exact head: 2,605 passed / 3 skipped / 0 failed.
  • Five targeted regression rows fail against the previous schema builder/parser with successful compilation: three previously accepted required-arity/default declarations and two enum diagnostic changes. Exact head sources restored and rebuilt afterward; checkout clean. The enum rows already refused execution previously; these validate a diagnostic change, not newly rejected input.
  • Additional public-API probes pass for C# and DefaultParameterValue metadata, inferred/defaulted options, explicit ZeroOrOne and ZeroOrMore, DI-before-lower-bound precedence, required absence, group property initializers and scalar enum repeats.
  • Prospective merge with target: conflict-free, tree 9c4b8d010bee53fb568e50c702db41aa0634a2e9, identical to GitHub PR merge-ref tree with the expected parents. Release solution build clean; same six suites: 2,617 passed / 3 skipped / 0 failed. Public arity probes and the previous raw MCP confidentiality/concurrent-log probes also pass on this combined tree.
  • Applicable CI Linux/Windows/macOS, packaging, protocol Inspector and smoke checks are successful. External review skipped for credits is not counted as independent evidence.

Independent static review found no additional issue in the changed schema/arity/parser surface. Its two other alerts were rejected after attribution checks: Telnet encoding and MCP diagnostic differences came from fixes #162/#163 on newer main, not changes introduced by this PR. Neither file is in the merge-base-to-head patch, and the combined tree preserves both fixes byte-for-byte; their regression tests pass.

The breaking Map-time refusal is deliberate, bounded to explicit required arity plus a handler default, and migration guidance is present. Inferred arity, optional explicit arity and documented DI fallback stay intact.

Approved. No merge or product modifications performed.

@carldebilly
carldebilly merged commit 65dd715 into main Nov 3, 2026
16 checks passed
@carldebilly
carldebilly deleted the dev/cdb/option-schema-followups branch November 3, 2026 04:44
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.

Follow-ups from PR #63 review panel (low severity)

2 participants