chore(deps): Bump NCalcSync from 6.4.0 to 7.1.0 - #96
Conversation
310bbec to
303acd6
Compare
check_dependabot_claims.py only looked at .csproj PackageReference pins, so a transitive-only update — a security bump to something no csproj names — would have failed the check. That is the most costly PR to block on a false positive. Lock files are safe to trust here: in #130 the lock file recorded Daqifi.Core at 1.3.0 right alongside the csproj, because the bump landed nowhere. Re-verified against the repo's real Dependabot PRs — still passes #93/#95/#96, still fails #130 on all ten unapplied claims. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… one Qodo, correctly: accepting a claim because SOME manifest reached the new version lets a grouped multi-directory PR move one head and leave another stale. Avalonia.Fonts.Inter is pinned by three projects here, so that is a real input shape, not a hypothetical. Now every project pinning the package must be at the claimed version — scoped to the `directories` Dependabot actually manages, read from dependabot.yml at check time. The scope matters in both directions: the iOS head is not managed, so its pins drift on purpose and must not fail a PR that could never have touched them; and if the list grows later, the check grows with it. An unreadable config is exit 2, never a silently widened scope. Qodo's suggested fix — carrying per-claim directory context out of the PR body — does not work: Dependabot dedupes a package across directories, so a grouped body states each bump once regardless of how many directories it touches. Lock files stay evidence-only, never grounds for failure. A legitimate single-directory PR leaves the other directories' lock files recording the old transitive version (#93 changed only Daqifi.Avalonia/), so failing on that would reject good PRs. Re-verified against the repo's real Dependabot PRs: passes #93/#95/#96, fails #130 on all ten unapplied claims, and the scope correctly excludes the iOS head. Self-test grows to 28 cases, including Qodo's exact scenario. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…pped (#137) * chore(deps): make Daqifi.Core updates visible instead of silently skipped Daqifi.Core sat at 1.3.0 for five weeks while four releases shipped, and nothing said so. The assumption was that Dependabot had never opened a PR for it. It had — twice — but never in a way anyone could see: #93 bumped Core 1.3.0 -> 1.4.0, titled "the minor-and-patch group with 3 updates"; Core appears nowhere in the title. #95 superseded it with 1.3.0 -> 1.5.0, titled after Avalonia. 08-17 Dependabot auto-closed #95 and opened no replacement. Two weeks of silence while 1.6.0 and 1.7.0 shipped. #130 announced Core 1.3.0 -> 1.7.0 in its body and never touched the csproj. Ten of its fourteen announced updates are missing from the diff. The NU1605 downgrade theory does not explain it: Core 1.4.0/1.5.0/1.6.0 all depend on System.IO.Ports 10.0.10, exactly what was pinned. Only 1.7.0 raised the floor. Three guards, one per failure: - Daqifi.Core is excluded from the minor-and-patch group, so it always gets its own "Bump Daqifi.Core from X to Y" PR — visible in a PR list, and not droppable from a group whose other members moved. - check_dependabot_claims.py fails a Dependabot PR whose body claims a bump its manifests do not show. Verified against this repo's history: passes #93/#95/#96, fails #130 on all ten unapplied claims. - check_core_drift.py compares the pin against nuget.org weekly and files a rolling issue, independent of Dependabot having done anything at all. Both guards ship with self-tests, and build.yml now runs every .github/scripts self-test on each push and PR — without that, these two would only be exercised on a Dependabot PR or on a Monday. .github/dependency-updates/README.md records the investigation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(ci): count lock files as evidence a claimed bump landed check_dependabot_claims.py only looked at .csproj PackageReference pins, so a transitive-only update — a security bump to something no csproj names — would have failed the check. That is the most costly PR to block on a false positive. Lock files are safe to trust here: in #130 the lock file recorded Daqifi.Core at 1.3.0 right alongside the csproj, because the bump landed nowhere. Re-verified against the repo's real Dependabot PRs — still passes #93/#95/#96, still fails #130 on all ten unapplied claims. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(ci): check a claimed bump in every project that pins it, not just one Qodo, correctly: accepting a claim because SOME manifest reached the new version lets a grouped multi-directory PR move one head and leave another stale. Avalonia.Fonts.Inter is pinned by three projects here, so that is a real input shape, not a hypothetical. Now every project pinning the package must be at the claimed version — scoped to the `directories` Dependabot actually manages, read from dependabot.yml at check time. The scope matters in both directions: the iOS head is not managed, so its pins drift on purpose and must not fail a PR that could never have touched them; and if the list grows later, the check grows with it. An unreadable config is exit 2, never a silently widened scope. Qodo's suggested fix — carrying per-claim directory context out of the PR body — does not work: Dependabot dedupes a package across directories, so a grouped body states each bump once regardless of how many directories it touches. Lock files stay evidence-only, never grounds for failure. A legitimate single-directory PR leaves the other directories' lock files recording the old transitive version (#93 changed only Daqifi.Avalonia/), so failing on that would reject good PRs. Re-verified against the repo's real Dependabot PRs: passes #93/#95/#96, fails #130 on all ten unapplied claims, and the scope correctly excludes the iOS head. Self-test grows to 28 cases, including Qodo's exact scenario. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(ci): measure Core drift from the oldest pin, not the first one read Same class of bug Qodo found in the sibling guard: check_core_drift.py returned the first manifest pinning Daqifi.Core and stopped. Two projects pinning it at different versions would report whichever happened to be read first — which could report "up to date" while another project sat four releases back. Drift is now measured from the oldest pin, with disagreeing pins called out explicitly, and the verdict no longer depends on manifest order. Today only Daqifi.Avalonia.csproj pins Core, so this changes nothing about the current repo; it stops the guard going quiet the moment that is no longer true. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * style(ci): early-continue the lock-file walk instead of a wide ternary Drops a 92-character line to within the file's own width; no behaviour change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(ci): keep every Daqifi.Core reference, not one per project file Qodo, correctly: pinned_versions keyed by manifest path, so a second reference to the package in the SAME project overwrote the first. Conditional ItemGroups per framework or RID are an ordinary MSBuild shape, and since drift is measured from the oldest pin, a newer reference could hide an older one and report the repo current while a conditional pin sat four releases back. It now returns every (version, manifest) pair. Ties resolve by manifest name rather than filesystem order, so the reported file is stable across runs. check_dependabot_claims.py does not share this: it keeps a set of versions per package per file, so a duplicate reference at a stale version already fails the claim. Tests cover both orderings of a doubly-referenced project — the verdict must not depend on which reference is read last. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…at fixes them (#140) * deps: document the lock-file commit every shared-library Dependabot PR needs, and script it #139 left a decision open: the Android head is in Dependabot's `directories` but Dependabot cannot refresh its packages.lock.json, so the choice was between documenting a manual refresh and dropping the head the way the iOS head is dropped. This takes the first option, because investigating it turned up a bigger problem that decides the question. Four of the five app lock files reach their packages through a ProjectReference to Daqifi.Avalonia and record its full transitive closure. Dependabot rewrites the lock file only in the directory whose manifest it edited. So a one-line bump in the shared library invalidates five lock files and refreshes one, and locked mode fails the other four with NU1004. That is 23 of the 28 packages managed here, and it is the current state of the repo: #96 and #130 are both red on it now, on the Android and iOS heads alike. That refutes the alternative. Dropping /Daqifi.Avalonia.Android would fix nothing — its NU1004 comes from the ProjectReference closure, not from its own two pins, and the iOS head proves it by already being out of `directories` and failing identically. The guard offered as cover cannot help either: avalonia-graph `needs: [desktop, android, ios]`, so it is SKIPPED on exactly the PRs in question. Dropping the head would only cost the one automated watch on Avalonia.Android. Reproduced on the pinned SDK 10.0.302 by doing what Dependabot does — bump Sentry 6.8.0 -> 6.9.0 in the shared library, refresh only its own lock file, then restore each head in locked mode. All four fail NU1004; the new script makes all four pass. - refresh_lock_files.sh regenerates all six lock files. It refuses to do a partial job: wrong SDK or a missing android/ios workload exits 2 without writing, because a half-refresh looks finished and leaves the skipped head failing NU1004 anyway. $DOTNET is authoritative rather than one candidate among several. It iterates projects rather than the slnx, which does not contain AvaloniaCapture, and never passes -r, which would prune the lock file to one RID. - test_refresh_lock_files.py drives it with a stub dotnet across four refusal cases and asserts nothing is written. Picked up by the existing `scripts` job, which globs test_*.py. Verified to fail when the refusal is removed. - The README section that deferred this decision now records it, and the dependabot.yml comment says which PRs are affected before someone tries to merge one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(ci): roll back the lock files when a refresh fails partway Qodo review on #140, finding 2. The preflight refuses to start without the pinned SDK and both workloads, but once restores begin they run one project at a time — so a failure on the fourth left the first three already rewritten. That is the same partial refresh the preflight exists to prevent, arriving by a different door, and it looks like an ordinary refresh diff on the way out. The script now snapshots every lock file before the first restore and rolls all of them back on failure, exiting 1. The snapshot is of the WORKING TREE, not HEAD: on a Dependabot branch the shared library's lock file is already legitimately modified, and rolling back to HEAD would discard Dependabot's own work along with ours. Exit codes are now 0 refreshed / 1 a restore failed, rolled back / 2 could not run, which lines up with the contract the other scripts here follow. The self-test grows a rollback group: a stub dotnet that mutates each lock file it restores and fails on the third. It carries a CONTROL case whose stub never fails, because a rollback test whose stub never wrote anything would pass without proving anything. Verified to fail when the rollback call is removed — three lock files left modified. Also records what the review's other finding got wrong. --force-evaluate IS what overrides RestoreLockedMode, so CI=true does not block the refresh. NuGet's own NU1004 text says so, and it is verified: same state, obj cleared, CI=true, RestoreLockedMode evaluating true — a plain restore fails NU1004 and the same restore with --force-evaluate regenerates the lock file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
303acd6 to
3e7d767
Compare
|
Rebased onto The red CI was never about NCalc. Each head's This is a major version, so the behaviour was measured, not assumedNCalc is reached from exactly one place — A standalone probe replaying that exact sequence under 6.4.0 and 7.1.0 over 27 expressions produced byte-identical output — same values, same CLR types, same exception types on the invalid cases:
The upgrade is behaviour-neutral for every expression this app can construct. Other gates, on SDK 10.0.302 with
|
| gate | result |
|---|---|
| locked restore, all six projects | succeeds, rewrites nothing |
| library / Desktop / AvaloniaCapture / iOS, Release | build succeeded, 0 errors |
lock files after the iossimulator-arm64 build |
untouched |
| unit tests | 336/336 passed |
check_dependabot_claims.py |
claim applied |
No new warnings — origin/main measured in the same worktree, --no-incremental, is 246 / 246 / 247 / 247, and this branch reports the same four.
One thing worth saying plainly: the reason this needed a hand-built probe is that the scaling path has no test. That gap outlives this PR and belongs in its own change, not here.
🤖 Generated with Claude Code
|
@dependabot rebase |
|
Looks like this PR has been edited by someone other than Dependabot. That means Dependabot can't rebase it - sorry! If you're happy for Dependabot to recreate it from scratch, overwriting any edits, you can request |
Rebased onto current main by hand: the original dependabot commit went CONFLICTING once main's lock files moved underneath it, and `@dependabot rebase` did not pick it up. Regenerated all six packages.lock.json files with a plain `dotnet restore` (no `-r`, so no RID narrowing and no NU1004 on CI's locked-mode restore). The lock diff is NCalc-only: NCalcSync 6.4.0 -> 7.1.0, NCalc.Core/NCalc.Parser replacing NCalc.Domain, Parlot and ExtendedNumerics.BigDecimal moving with it, plus a transitive patch bump of Microsoft.Extensions.Logging.Abstractions 10.0.7 -> 10.0.10. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3e7d767 to
7fd2d74
Compare
|
Rebased this by hand onto current What changed vs. the old head, nothing but a re-derivation of the same bump:
Gate, run locally on The part that was not verifiable beforeThis is a major version bump of the library that evaluates user-entered channel scaling So I wrote characterisation tests for it and ran them against both versions from one working Those tests are in #221, separately, so they land whether or not this bump does and guard the Caveat that survives: the guarantee is coverage-shaped, not absolute. Every NCalc construct |
Updated NCalcSync from 6.4.0 to 7.1.0.
Release notes
Sourced from NCalcSync's releases.
7.1.0
What's Changed
incomparisons when NoStringTypeCoercion is set by @cokert in Fix: Honor StringComparer atincomparisons when NoStringTypeCoercion is set ncalc/ncalc#614NCalc docs re-design
With the help of Hallmark. Check it here: https://ncalc.github.io/ncalc
New Contributors
incomparisons when NoStringTypeCoercion is set ncalc/ncalc#614Full Changelog: ncalc/ncalc@v7.0.2...v7.1.0
7.0.2
What's Changed
ExpressionContextby @gumbarros in Fix: Preserve dictionary comparers when copyingExpressionContextncalc/ncalc#608Full Changelog: ncalc/ncalc@v7.0.1...v7.0.2
7.0.1
What's Changed
Full Changelog: ncalc/ncalc@v7.0.0...v7.0.1
7.0.0
What's Changed
ExpressionConfiguration,ExpressionEvaluationOptionsfor explicit configuration.FloatingPointNumberTypeandIntegerNumberTypeto configure parser number handling and string-to-number coercion in math helpers.Breaking Changes
ExpressionContextnow represents only per-evaluation runtime state.StaticParameterswas renamed toParameters, andOptions,CultureInfo,MathHelperOptions,ComparisonOptions, and the implicit conversions fromExpressionOptions/CultureInfowere removed. Configure parsing and evaluation withExpressionConfigurationinstead.ExpressionContextis no longer arecordand all props are init only to incentive immutability.Expression.Optionsno longer exposes the getter. It is kept only as a setter that replacesExpression.ConfigurationusingExpressionConfiguration.FromOptions(...). UseExpression.Configuration,Expression.ParserOptions,Expression.EvaluationOptions,Expression.CultureInfo, andExpression.Configuration.CacheEnabled.Expressionconstructors andIExpressionFactory.Createnow acceptExpressionConfigurationandCultureInfo.Parameters,DynamicParameters,AsyncParameters,Functions, andAsyncFunctionsonExpressionno longer have setters. Mutate the dictionaries onExpression.Contextor replace them through a newExpressionContext.LogicalExpressionArgumentSeparatorwas renamed toArgumentSeparator.LogicalExpressionParserOptionsno longer exposesDecimalAsDefaultandLongAsDefault. UseFloatingPointNumberTypeandIntegerNumberType.LogicalExpressionParser.GetOrCreateExpressionParsernow requires aCultureInfo, andLogicalExpressionParser.Parseaccepts culture separately from parser options.ILogicalExpressionFactory.Createnow acceptsLogicalExpressionParserOptions?andCultureInfo?instead ofExpressionOptions.IEvaluationVisitorFactory,EvaluationVisitor, andAsyncEvaluationVisitornow requireExpressionEvaluationOptionsandCultureInfo.LogicalExpressionextension methodsEvaluate(...)andEvaluateAsync(...)were removed. Evaluate throughExpressionor instantiate the appropriate evaluation visitor.ComparisonOptionswas removed. UseStringComparerproperty.MathHelperOptionswas renamed toMathOptions.LogicalExpressionParserContextwas renamed toLogicalExpressionParseContextfollowing Parlot conventionNCalc.Antlrpackage/plugin was removed. Use the default Parlot parser or provide a customILogicalExpressionFactory.Migration Guide: https://ncalc.github.io/ncalc/articles/project/migrate_v6_to_v7.html
Full Changelog: ncalc/ncalc@v6.4.0...v7.0.0
Commits viewable in compare view.