Skip to content

feat: bulk operations, connection pooling, and migration CLI enhancements#19

Merged
joshsmithxrm merged 49 commits intomainfrom
feature/cli-implementation
Dec 23, 2025
Merged

feat: bulk operations, connection pooling, and migration CLI enhancements#19
joshsmithxrm merged 49 commits intomainfrom
feature/cli-implementation

Conversation

@joshsmithxrm
Copy link
Copy Markdown
Owner

Summary

Major feature release adding high-performance bulk operations, intelligent connection pooling, and migration CLI tooling.

Bulk Operations (PPDS.Dataverse)

  • Parallel batch processing using CreateMultiple, UpdateMultiple, UpsertMultiple APIs
  • Progress reporting with IProgress<ProgressSnapshot> for real-time throughput metrics
  • Server-recommended parallelism via RecommendedDegreesOfParallelism (can be overridden for higher throughput)

Connection Pooling

  • Throttle-aware connection selection - routes around throttled connections
  • Connection health management - marks invalid connections, prevents pool leaks
  • Dynamic pool expansion with spin-wait to prevent over-creation

Resilience & Retry Logic

  • TVP race condition retry (SQL 3732) - handles transient errors on new tables ✅ production-validated
  • SQL deadlock retry (SQL 1205) - handles contention under high parallelism
  • Service protection throttle retry (429) - exponential backoff with intelligent routing

Migration CLI (ppds-migrate)

  • Schema generation from live Dataverse environments
  • M2M relationship export/import with CMT format compatibility
  • User mapping for cross-environment migrations
  • Plugin disable/enable during imports
  • Attribute filtering for selective exports

Documentation

  • Performance benchmarks (validated ~1.8M records/hour at parallelism 50)
  • Architecture Decision Records (ADRs)
  • Detailed specs for throttle detection, connection health, TVP retry

CI/CD

  • Added CodeQL security scanning workflow

Test Results

  • 42,366 records upserted at parallelism 50
  • 100% success rate (0 failures)
  • Duration: 83 seconds (~508 records/sec)
  • TVP retry triggered and succeeded during test run

Validation Status

Feature Status
Bulk operations ✅ Production-validated
Connection pooling ✅ Production-validated
TVP retry (3732) ✅ Production-validated
Deadlock retry (1205) ✅ Code-complete (follows validated TVP pattern)
Throttle retry (429) ✅ Code-complete (not triggered in test - no 429s hit)

Breaking Changes

None. All changes are additive.

Commits

  • feat(dataverse): add SQL deadlock retry to bulk operations
  • refactor(dataverse): centralize error handling in batch execution wrapper
  • feat(dataverse): implement connection health management and TVP retry
  • feat(dataverse): implement throttle detection and intelligent routing
  • feat(dataverse): use RecommendedDegreesOfParallelism by default
  • fix(dataverse): fix connection pool leak and retry logic
  • feat(dataverse): add progress reporting to bulk operations
  • feat: add parallel batch processing, progress tracking, and bug fixes
  • feat: implement M2M relationship export/import
  • feat: add schema generation and improve dependency detection
  • ci: add security scanning workflows

🤖 Generated with Claude Code

joshsmithxrm and others added 30 commits December 20, 2025 11:37
- Add CodeQL workflow for C# static analysis (security-and-quality queries)
- Add dependency-review-action to block PRs with high severity vulnerabilities
- Add dotnet list package --vulnerable check to build workflow
- Dependency check warns but doesn't fail (handles transitive dependency issues)
CLI Implementation:
- Add ServiceFactory for DI container setup
- Wire ExportCommand to IExporter (ParallelExporter)
- Wire ImportCommand to IImporter (TieredImporter)
- Wire AnalyzeCommand to ICmtSchemaReader + IDependencyGraphBuilder
- Wire MigrateCommand for export→import flow
- Fix import error order (validate file before connection)

CMT Compatibility Fixes:
- Add 'etc' attribute (ObjectTypeCode) to entity element
- Change 'm2m' to 'manyToMany' for relationships
- Add full relationship attributes (referencingEntity, referencingAttribute, etc.)
- Add 'primaryKey' attribute support for fields
- Add IsPrimaryKey property to FieldSchema

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add `schema generate` command to create migration schemas from Dataverse metadata
- Add `schema list` command to browse available entities with filtering
- Write CMT-compatible schema format (etc, primaryidfield, lookupType, relationships)
- Handle polymorphic lookups (e.g., account|contact) in dependency analysis
- Add entityreference type to IsLookup detection
- Include explicit <relationships> section for enhanced dependency detection

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add dateMode="absolute" attribute to schema root (required by CMT)
- Add <entityImportOrder> section to schema (required by CMT)
- Change data.xml to use element content for values instead of attributes
- Update date format to CMT-compatible "yyyy-MM-dd HH:mm:ss"
- Update boolean format to "1"/"0" instead of "true"/"false"

Fixes "Invalid import file" error when importing into CMT.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Read lookup GUID from element content (CMT format)
- Add "entityreference" to lookup type handling
- Fix boolean parsing to handle "1"/"0" values

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add [Content_Types].xml to ZIP (required by CMT)
- Use value attribute instead of element content for field values
- Add xmlns:xsd and xmlns:xsi namespaces to data.xml root
- Use displayname attribute on entity (not recordcount)
- Include primary ID field in record output
- Add m2mrelationships element after records
- Fix DateTime format to ISO 8601 with 7 decimal places
- Remove dateMode attribute and entityImportOrder from schema
- Remove customfield attribute from field elements
- HTML-encode filter content using WriteElementString
- Fix field attribute order: displayname, name, type

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ibility

- Add IsReflexive and TargetEntityPrimaryKey to RelationshipSchema
- Create ManyToManyRelationshipData class with grouped target model
- Update CmtSchemaReader/Writer to handle M2M attributes (isreflexive, m2mTargetEntityPrimaryKey)
- Update CmtDataReader to parse <m2mrelationships> element
- Update CmtDataWriter to write <m2mrelationships> with grouped targets
- Add M2M export to ParallelExporter (queries intersect entities)
- Rewrite ProcessRelationshipsAsync in TieredImporter with role entity lookup
- Support AssociateRequest with multiple targets per source

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Attribute Filtering:
- Add IncludeAttributes, ExcludeAttributes, ExcludeAttributePatterns to SchemaGeneratorOptions
- Update DataverseSchemaGenerator to apply attribute filtering
- Add CLI options: --include-attributes, --exclude-attributes, --exclude-patterns

User Mapping:
- Add UserMapping and UserMappingCollection models
- Add UserMappingReader for XML user mapping files
- Update TieredImporter to apply user mappings for systemuser/team references
- Add CLI option: --user-mapping

Plugin Disable/Enable:
- Add PluginStepManager to query and disable/enable plugin steps
- Update TieredImporter to disable plugins during import based on schema disableplugins attribute
- Re-enable plugins in finally block to ensure cleanup
- Register IPluginStepManager in DI container

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The M2M relationship Entity1/Entity2 must be relative to the current
entity being processed, not the fixed order from Dataverse metadata.

Bug: When Dataverse returned Entity1LogicalName != current entity,
we would set Entity2 to the wrong entity, causing:
- systemuser M2M to team → exported with targetentityname="systemuser"
- Import then looks for team with systemuser's GUID → fails

Fix: Determine source/target based on which entity matches metadata.LogicalName
- Also set IsReflexive for self-referencing M2M relationships
- Set TargetEntityPrimaryKey from the target intersect attribute

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 4 to 5.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](actions/setup-dotnet@v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
---
updated-dependencies:
- dependency-name: coverlet.collector
  dependency-version: 6.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: coverlet.collector
  dependency-version: 6.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: coverlet.collector
  dependency-version: 6.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
---
updated-dependencies:
- dependency-name: FluentAssertions
  dependency-version: 8.8.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
---
updated-dependencies:
- dependency-name: Microsoft.Extensions.DependencyInjection
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: Microsoft.Extensions.DependencyInjection
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
…Microsoft.Extensions.Logging.Abstractions

Bumps Microsoft.Extensions.DependencyInjection.Abstractions from 8.0.2 to 10.0.1
Bumps Microsoft.Extensions.Logging.Abstractions from 8.0.3 to 10.0.1

---
updated-dependencies:
- dependency-name: Microsoft.Extensions.DependencyInjection.Abstractions
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: Microsoft.Extensions.Logging.Abstractions
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: Microsoft.Extensions.DependencyInjection.Abstractions
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: Microsoft.Extensions.Logging.Abstractions
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
…Microsoft.Extensions.Options

Bumps Microsoft.Extensions.DependencyInjection.Abstractions from 8.0.2 to 10.0.1
Bumps Microsoft.Extensions.Options from 8.0.2 to 10.0.1

---
updated-dependencies:
- dependency-name: Microsoft.Extensions.DependencyInjection.Abstractions
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: Microsoft.Extensions.Options
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: Microsoft.Extensions.DependencyInjection.Abstractions
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: Microsoft.Extensions.Options
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Add validation in DataverseConnectionPool that detects when connections
target different Dataverse organizations and logs a warning. This prevents
the common misconfiguration of putting Dev/QA/Prod in the same pool,
which causes requests to be randomly load-balanced across environments.

Also add documentation in README explaining:
- Why multiple orgs in one pool is wrong
- The correct pattern for multi-environment scenarios
- When multiple connections in one pool IS appropriate

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PPDS.Dataverse:
- Add ProgressTracker utility for thread-safe progress calculation
- Add ProgressSnapshot record with instant/overall rates and ETA
- Add MaxParallelBatches option to BulkOperationOptions
- Implement parallel batch processing in BulkOperationExecutor
- Convert BulkOperationResult to record for immutability

PPDS.Migration:
- Fix Entity.Id not used by UpsertMultiple (add as attribute)
- Add SuccessCount/FailureCount to ProgressEventArgs
- Fix TieredImporter to report success/failure breakdown
- Fix deferred fields progress to set Field, Current, Total
- Pass Errors array to progress.Complete()

ConsoleProgressReporter:
- Show success/failure breakdown during import
- Display detailed errors in completion summary (up to 10)
- Handle null Field gracefully in deferred fields display
- Add color-coded output for success/warnings/errors

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document the duplicate key error that occurs when setting alternate key
columns in both KeyAttributes and Attributes. The server's internal
ClassifyEntitiesForUpdateAndCreateV2 processor copies KeyAttributes into
Attributes, causing Dictionary.Insert to fail with "An item with the
same key has already been added".

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add IProgress<ProgressSnapshot> parameter to IBulkOperationExecutor methods
- Wire up ProgressTracker in BulkOperationExecutor for real-time progress
- Report progress after each batch completion (both parallel and sequential)

Usage:
var progress = new Progress<ProgressSnapshot>(snapshot =>
    Console.WriteLine($"{snapshot.Processed}/{snapshot.Total} ({snapshot.PercentComplete:F1}%)"));

await executor.UpsertMultipleAsync(entityName, entities, options, progress);

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add LogDebug calls before and after each batch execution in
BulkOperationExecutor for CreateMultiple, UpdateMultiple, and
UpsertMultiple operations.

With --verbose (Debug level logging), users will now see:
  dbug: Executing UpsertMultiple batch. Entity: account, BatchSize: 1000
  dbug: UpsertMultiple batch completed. Entity: account, Success: 1000

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…play

- Add RatePerSecond property that returns OverallRatePerSecond
- Add warning to InstantRatePerSecond about volatility in batch operations
- Add BULK_OPERATIONS_BENCHMARKS.md to document performance testing

The InstantRatePerSecond fluctuates wildly when batches complete in bursts.
Use RatePerSecond (overall rate) for display and throughput reporting.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix InitializeMinimumConnections to count active connections, not just
  idle ones. Previously, validation loop created new connections every
  60s when active connections weren't counted toward the minimum.
- Add PoolExhaustedException for typed exception handling
- Add retry logic with exponential backoff (1s, 2s) for pool exhaustion
- Fix dead code in retry loop where final attempt was unreachable

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When pool is empty but connections are active (about to be returned),
add a brief 5ms spin-wait before creating a new connection. This handles
the race condition where:
1. Worker A logs "batch completed" but hasn't returned connection yet
2. Worker B starts new batch and sees empty pool
3. Worker B creates new connection (unnecessary)
4. Worker A's connection is then returned (now we have an extra)

The spin-wait allows in-flight connection returns to complete, reducing
unnecessary pool expansion from 50 connections down to ~5-8 for a
4-worker parallel batch operation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…osal flag

The PooledClient._disposed flag was set on first Dispose() and never
reset, causing subsequent checkouts of the same connection to silently
skip returning to pool. This caused connection exhaustion under load.

Changes:
- Rename _disposed to _returned to clarify semantics (returning to pool, not disposing)
- Reset _returned flag in Reset() when connection is returned to pool
- Add _poolLock for synchronized queue access
- Use Interlocked operations for thread-safe flag management
- Pass CancellationToken through Parallel.ForEachAsync to batch methods

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Results from testing connection pool vs single ServiceClient:
- Connection pool is 5% faster than single ServiceClient (47.7/s vs 45.4/s)
- Batch size 100 is 3% faster than batch size 1000
- Updates are ~23% slower than creates (alternate key lookup overhead)

Optimal config: Connection Pool + Batch Size 100 = 47.7 records/sec

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update CLAUDE.md with PPDS.Dataverse project structure and performance rules
- Add Microsoft's reference throughput benchmarks (10M records/hour for bulk APIs)
- Add batch size guidance based on our benchmarks (100 vs 1000)
- Add RecommendedDegreesOfParallelism / x-ms-dop-hint guidance
- Add Performance Settings section documenting auto-applied settings
- Add Microsoft Learn reference links to all ADRs
- Document service protection limits (6K requests, 20min execution, 52 concurrent)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change BatchSize default from 1000 to 100 (benchmarked optimal)
- Change MaxParallelBatches to nullable, default null
- When null, automatically use ServiceClient.RecommendedDegreesOfParallelism
  (from x-ms-dop-hint header per Microsoft recommendation)
- Add ResolveParallelismAsync helper to resolve parallelism for all bulk ops
- Fall back to sequential (1) if RecommendedDegreesOfParallelism unavailable

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Log warning if MaxParallelBatches > MaxPoolSize since effective
parallelism will be limited by available pool connections.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two comprehensive specification documents for enterprise-grade features:

1. THROTTLE_DETECTION_AND_ROUTING.md
   - Wire up existing ThrottleTracker infrastructure
   - Detect service protection errors (all 3 error codes)
   - Extract Retry-After from OrganizationServiceFault.ErrorDetails
   - Intelligent routing: try different connection first, wait only when all throttled
   - Expose throttle statistics to consumers

2. CONNECTION_HEALTH_MANAGEMENT.md
   - Health-based connection recycling (not fixed timer)
   - Connection validation on checkout (IsReady, age, validity)
   - Auth and connection failure detection and recovery
   - MarkInvalid() for explicit connection invalidation
   - Retry failed operations with new connections
   - Configurable MaxLifetime (default 60min vs current 30min)

Both specs include:
- Problem statement and Microsoft guidance with references
- Current state analysis
- Detailed implementation with code examples
- Testing requirements and acceptance criteria
- Risk mitigations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
joshsmithxrm and others added 10 commits December 23, 2025 03:34
Add parallelism 50 results showing 508.6 rec/s (8.4x improvement over
server-recommended). Document when to use standard vs high-throughput
mode and note that multi-app-registration pooling is untested but
could potentially increase throughput further.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove unused variable in ParallelExporter.cs (error)
- Refactor foreach loops to use LINQ Where/Select patterns
- Improve exception handling in DataverseSchemaGenerator.cs with specific catch blocks

Files changed:
- ParallelExporter.cs: Remove dead code, use LINQ for filtering
- SchemaGeneratorOptions.cs: Replace foreach+if with LINQ Any
- CmtDataReader.cs: Use LINQ for parsing target IDs
- ThrottleTracker.cs: Simplify cleanup with LINQ Where
- DependencyGraphBuilder.cs: Use LINQ pipeline for edge creation
- DataverseConnectionPool.cs: Use LINQ for connection string parsing
- DataverseSchemaGenerator.cs: Add specific exception catches

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add direct reference to System.Security.Cryptography.Pkcs 8.0.x to
override the vulnerable 6.0.1 version pulled in by Dataverse.Client.

Resolves: GHSA-555c-2p6r-68mm (High severity)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ExecuteAsync to pool that retries indefinitely on service protection
- PooledClient auto-records throttle via callback to pool
- GetClientAsync waits for non-throttled connection BEFORE acquiring semaphore
- ThrottleAwareStrategy filters throttled connections, falls back to shortest expiry
- BulkOperationExecutor simplified: no MaxThrottleRetries, pool handles waiting
- Service protection is transient - never fail, only CancellationToken stops retry

Key fix: Throttle waiting no longer holds semaphore slots, preventing
PoolExhaustedException when all connections are throttled.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@joshsmithxrm joshsmithxrm force-pushed the feature/cli-implementation branch from f56dacd to fd32687 Compare December 23, 2025 21:28
Removed the unused `lastException` variable and its assignments in
ExecuteBatchWithThrottleHandlingAsync. The variable was assigned in
4 catch blocks but never read - each catch block either throws the
original exception or continues to retry.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@joshsmithxrm
Copy link
Copy Markdown
Owner Author

@gemini-code-assist review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This is a massive and impressive feature release that adds high-performance bulk operations, intelligent connection pooling, and a comprehensive migration CLI. The level of detail in the new documentation, ADRs, and specifications is excellent and provides great context for the design decisions. The implementation is generally of very high quality, introducing sophisticated and resilient patterns for parallelism, throttle handling, and error recovery. I've identified one critical issue regarding a potential stack overflow in the connection pool and a medium-severity maintainability issue in a constructor. Overall, this is a fantastic contribution that significantly enhances the SDK's capabilities.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot reviewed 68 out of 68 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

joshsmithxrm and others added 2 commits December 23, 2025 16:04
Replaced recursive call in GetConnectionFromPoolCore with a while loop
that drains invalid connections. This eliminates theoretical stack
overflow risk while maintaining identical behavior:

- Loop continues until valid connection found OR pool is empty
- Invalid connections are disposed and removed from pool
- When pool exhausted, creates new connection
- Slightly more efficient (no function call overhead per iteration)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- ADR-0005: Pool sizing per connection (MaxConnectionsPerUser default)
- Structured Configuration Spec: Typed config with Key Vault/env var support
- Multi-Environment Spec: Named environments and live migration design

These specs document the approved designs for implementation on a future branch.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@joshsmithxrm joshsmithxrm merged commit 4d72360 into main Dec 23, 2025
5 checks passed
@joshsmithxrm joshsmithxrm deleted the feature/cli-implementation branch December 25, 2025 10:10
joshsmithxrm pushed a commit that referenced this pull request Jan 8, 2026
…es (#19)

Bumps the development-dependencies group with 4 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin), [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser), [@vscode/vsce](https://github.com/Microsoft/vsce) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `@typescript-eslint/eslint-plugin` from 8.47.0 to 8.48.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.48.0/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.47.0 to 8.48.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.48.0/packages/parser)

Updates `@vscode/vsce` from 3.7.0 to 3.7.1
- [Release notes](https://github.com/Microsoft/vsce/releases)
- [Commits](microsoft/vscode-vsce@v3.7.0...v3.7.1)

Updates `typescript-eslint` from 8.47.0 to 8.48.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.48.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.48.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.48.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: "@vscode/vsce"
  dependency-version: 3.7.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: typescript-eslint
  dependency-version: 8.48.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
joshsmithxrm added a commit that referenced this pull request Mar 15, 2026
Bug #11: Export now works with FetchXML queries. Added fetchXml parameter
to query/export RPC endpoint so FetchXML content is sent directly instead
of through the SQL parser (which crashes on XML).

Bug #15: Added expand chevron (›) indicator on solution component items
so users can discover they're clickable for detail cards.

Bug #18: Removed auto-collapse on component detail cards — multiple cards
can now be expanded simultaneously for comparison.

Bug #19: Solution list now shows uniqueName (friendlyName) format instead
of friendlyName only, matching developer workflow expectations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
joshsmithxrm added a commit that referenced this pull request Mar 16, 2026
Bug #11: Export now works with FetchXML queries. Added fetchXml parameter
to query/export RPC endpoint so FetchXML content is sent directly instead
of through the SQL parser (which crashes on XML).

Bug #15: Added expand chevron (›) indicator on solution component items
so users can discover they're clickable for detail cards.

Bug #18: Removed auto-collapse on component detail cards — multiple cards
can now be expanded simultaneously for comparison.

Bug #19: Solution list now shows uniqueName (friendlyName) format instead
of friendlyName only, matching developer workflow expectations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
joshsmithxrm added a commit that referenced this pull request Mar 18, 2026
Solutions (#1,#2,#3,#5): Include Managed toggle, sort controls,
Visible/API Managed fields, Maker Portal button, isVisible/isApiManaged
end-to-end C# support.

Import Jobs (#7,#8,#9): Search bar, Operation Context column
(end-to-end C#→TS), record count with filtered status.

Plugin Traces (#11,#12,#17,#18,#55): CRITICAL Trace Level dropdown
fix, Maker Portal URL fix (Dynamics 365 classic), status text labels,
record count, search bar.

Web Resources (#19): Restored Created By and Created On columns.

Connection References (#23,#24,#25,#28,#55): Expandable flow/connection
detail with chevron toggle, ISO timestamp formatting, search bar,
status badge improvements (Unknown/Unbound), Sync Settings button.

Environment Variables (#29,#31,#55): Modified On column restored,
search bar, Sync Settings button.

Metadata Browser (#37): Custom Only filter toggle for entities.

Data Explorer (#41,#42): Clear button, Import button (file dialog).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
joshsmithxrm added a commit that referenced this pull request Mar 19, 2026
Solutions (#1,#2,#3,#5): Include Managed toggle, sort controls,
Visible/API Managed fields, Maker Portal button, isVisible/isApiManaged
end-to-end C# support.

Import Jobs (#7,#8,#9): Search bar, Operation Context column
(end-to-end C#→TS), record count with filtered status.

Plugin Traces (#11,#12,#17,#18,#55): CRITICAL Trace Level dropdown
fix, Maker Portal URL fix (Dynamics 365 classic), status text labels,
record count, search bar.

Web Resources (#19): Restored Created By and Created On columns.

Connection References (#23,#24,#25,#28,#55): Expandable flow/connection
detail with chevron toggle, ISO timestamp formatting, search bar,
status badge improvements (Unknown/Unbound), Sync Settings button.

Environment Variables (#29,#31,#55): Modified On column restored,
search bar, Sync Settings button.

Metadata Browser (#37): Custom Only filter toggle for entities.

Data Explorer (#41,#42): Clear button, Import button (file dialog).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
joshsmithxrm added a commit that referenced this pull request Mar 19, 2026
* fix(cdp): use pwsh Expand-Archive for VSIX extraction on Windows

bsdtar interprets the C: drive prefix as a remote host, breaking
VSIX extraction in --vsix mode. Use PowerShell's Expand-Archive on
Windows; keep tar on other platforms.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* plan: extension UX audit fixes — 28 findings across 10 phases

Side-by-side comparison of legacy v0.3.4 vs new extension produced
55 findings. After triage: 28 fixes, 22 keep-new-behavior, 5 deferred.
Organized into 10 phases (1 cross-cutting + 9 per-panel) for parallel
agent execution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(ext): Phase 1 — cross-cutting infrastructure fixes

- Add Connection References + Environment Variables to sidebar Tools (#56, #57)
- Standardize command titles: "Open Data Explorer", "Open Plugin Traces" (#51)
- Remove text-transform: uppercase from 5 panel CSS files for Title Case headers (#10)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(ext): Phases 2-9 — UX audit fixes across all 8 panels

Solutions (#1,#2,#3,#5): Include Managed toggle, sort controls,
Visible/API Managed fields, Maker Portal button, isVisible/isApiManaged
end-to-end C# support.

Import Jobs (#7,#8,#9): Search bar, Operation Context column
(end-to-end C#→TS), record count with filtered status.

Plugin Traces (#11,#12,#17,#18,#55): CRITICAL Trace Level dropdown
fix, Maker Portal URL fix (Dynamics 365 classic), status text labels,
record count, search bar.

Web Resources (#19): Restored Created By and Created On columns.

Connection References (#23,#24,#25,#28,#55): Expandable flow/connection
detail with chevron toggle, ISO timestamp formatting, search bar,
status badge improvements (Unknown/Unbound), Sync Settings button.

Environment Variables (#29,#31,#55): Modified On column restored,
search bar, Sync Settings button.

Metadata Browser (#37): Custom Only filter toggle for entities.

Data Explorer (#41,#42): Clear button, Import button (file dialog).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ext): review fixes — colSpan bug and command injection

- Connection References: fix colCount from wrong heuristic (8) to
  correct value (7) matching actual column count
- CDP tool: sanitize paths for PowerShell injection (escape single
  quotes); use execFileSync for tar on Unix to avoid shell interpretation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style(ext): extract inline styles to CSS classes per Gemini review

Move search input and sort select inline styles to dedicated
.toolbar-search and .toolbar-select CSS classes across 4 panels
(Connection Refs, Env Variables, Import Jobs, Solutions).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ext): add missing webview entry points to knip config

The 6 non-query/solutions webview panels are esbuild entry points but
were missing from knip.json, causing false-positive unused-file reports.
Also un-export internal-only types from shared modules.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ext): solution filter GUID bug and raw ISO timestamps

- SolutionFilter shared component used uniqueName as option value
  instead of GUID id, causing "solutionId must be a valid GUID" error
  on Web Resources (and silently wrong on Conn Refs / Env Vars)
- Import Jobs and Web Resources rendered raw ISO timestamps; add
  formatDateTime helper matching Plugin Traces / Conn Refs pattern

Found by QA blind verification agents.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ext): review fixes — escaping, shell safety, URL normalization

- Solutions panel: escape rootComponentBehavior and boolean ternaries
  before innerHTML insertion (S1 compliance)
- Connection References: escape literal "Unbound" for consistent
  escaping discipline
- CDP tool: use execFileSync instead of execSync for PowerShell
  VSIX extraction (S2 compliance — no shell: true)
- Plugin Traces: strip trailing slash from environment URL before
  Maker Portal link construction

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ext): escape formatDate output in solutions detail card

Wrap formatDate() calls in escapeHtml() for consistent escaping
discipline — formatDate can return raw ISO string on parse failure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

3 participants