Skip to content

Add exact public configuration typing and runtime validation - #417

Draft
HardlyDifficult wants to merge 54 commits into
codex/exact-compensation-issuancefrom
codex/exact-public-config-state
Draft

HardlyDifficult wants to merge 54 commits into
codex/exact-compensation-issuancefrom
codex/exact-public-config-state

Conversation

@HardlyDifficult

@HardlyDifficult HardlyDifficult commented Jul 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • separate caller-facing configuration input from fully resolved runtime configuration
  • model OAuth2 and shared-secret authentication as discriminated unions
  • make OcpClient runtime state and error metadata explicit instead of relying on optional-property ambiguity
  • keep per-call issuer authorization coordinates atomic
  • add strict source and built-declaration probes under exactOptionalPropertyTypes
  • generate fallback UpdateCapTable command IDs with cryptographic UUIDs

Validation

  • npm run lint
  • npm run typecheck
  • npm run build
  • npm run test:declarations
  • npm run test:exact-public-config
  • npm run test:ci — 74 suites / 4,078 tests passed
  • coverage: 85.24% statements, 74.93% branches, 84.31% functions, 85.47% lines
  • exact-optional diagnostics in scoped configuration/auth/client/error files: 0
  • remaining repository-wide exact-optional diagnostics: 18, intentionally reserved for Enforce exact optional source boundaries #418

Stack

Depends on #416.


Note

Medium Risk
Touches client bootstrap, environment/auth resolution, and many command entry points; behavior changes mainly around invalid or hostile inputs, but mis-tuned validation could reject previously tolerated configs.

Overview
Tightens how callers configure OcpClient and Canton environments, with stricter TypeScript unions and runtime guards that only accept plain own-data objects (no proxies, accessors, or explicit undefined where omission is required).

Configuration types move to clientOptions and environment: OAuth2 vs shared-secret are discriminated unions, staging is added, and resolution/validation now throws OcpValidationError with structured issues instead of generic Error. OcpClient.forStaging, preset helpers, and fromEnv whitelist allowed keys per entry path and validate injected ledger/validator clients (including matching networks).

OcpClient construction snapshots dependencies, factory coordinates, and observability; issuer authorization uses a single optional factory object instead of separate contract/template IDs. Shared inspectExactObject / command-carrier helpers snapshot cap-table batch, archive, factory, and authorization parameters so later mutation or traps cannot affect submission.

Public error and observability shapes are made explicit under exactOptionalPropertyTypes (e.g. OcpValidationError.receivedValue always declared as unknown | undefined). Declaration checks and a new test:exact-public-config compile step enforce that contract; batch commandId generation switches to UUIDs, and failure/observability paths avoid unsafe coercion on rejections.

Reviewed by Cursor Bugbot for commit 92875cf. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Added staging environment preset support.
    • Exposed expanded client option types at the SDK entry point, including atomic factory-coordinate overrides.
  • Bug Fixes

    • Hardened runtime validation for client/environment setup, observability inputs, and issuer authorization.
    • Tightened structured error objects and “explicit undefined vs omission” behavior.
    • Improved snapshotting/immutability for command, batch, and configuration inputs.
  • Tests

    • Expanded exact/public configuration compile-time checks and strengthened runtime validation coverage.
  • Chores

    • Added exact-public-config TypeScript compilation and updated lint/test configuration.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds typed configuration contracts, immutable runtime snapshots, strict environment and client validation, atomic factory overrides, safer observability handling, explicit error property types, snapshot-based command execution, and comprehensive runtime and exact-optional-property tests.

Changes

Configuration and client safety

Layer / File(s) Summary
Type contracts and exact validation utilities
src/clientOptions.ts, src/observabilityTypes.ts, src/types/common.ts, src/utils/*
Adds public SDK contracts and exact-object, array, factory-coordinate, command-context, command-parameter, and observability snapshot utilities.
Environment resolution and presets
src/environment.ts
Adds staging support, discriminated authentication configuration, immutable presets, strict parsing, typed overrides, and resolved configuration snapshots.
Client construction and authorization
src/OcpClient.ts, src/functions/OpenCapTable/issuerAuthorization/*, src/index.ts
Validates injected dependencies and options, routes preset construction through resolved environments, and uses atomic factory coordinates for issuer authorization.
Command execution and observability
src/functions/OpenCapTable/capTable/*, src/functions/OpenCapTable/factory/createFactory.ts, src/observability.ts
Snapshots command parameters and observability inputs before submission, preserves immutable values, and derives bounded diagnostics for failures.
Error shapes and verification
src/errors/*, test/*, scripts/check-declarations.ts, package.json, tsconfig*.json, eslint.config.mjs
Updates error property declarations and adds runtime, type-level, declaration, environment, client, command, and observability validation coverage.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant OcpClient
  participant Environment
  participant AuthorizeIssuer
  participant Ledger
  participant Observability
  Caller->>OcpClient: construct with validated dependencies and options
  OcpClient->>Environment: validate and resolve environment
  Environment-->>OcpClient: immutable resolved configuration
  Caller->>OcpClient: authorize issuer with optional factory
  OcpClient->>AuthorizeIssuer: pass snapshotted issuer and factory
  AuthorizeIssuer->>Ledger: resolve network and submit authorization transaction
  Ledger-->>AuthorizeIssuer: transaction result or error
  AuthorizeIssuer->>Observability: record bounded submission diagnostics
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: exact public configuration typing plus runtime validation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/exact-public-config-state

Comment @coderabbitai help to get the list of available commands.

@HardlyDifficult
HardlyDifficult marked this pull request as ready for review July 10, 2026 04:53
@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

CI is green on the latest head, including the full OCP QuickStart integration suite.

@copilot review
@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

@HardlyDifficult Thanks for confirming CI is green. I'll go ahead and review the latest changes now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copilot AI 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.

Pull request overview

This PR tightens the public TypeScript configuration/client/error surface (notably for exactOptionalPropertyTypes) by separating caller input vs resolved runtime configuration, restructuring authentication and factory coordinates into more explicit/atomic shapes, and adding declaration-level compile-time probes to keep the published .d.ts contracts exact.

Changes:

  • Introduces stricter/discriminated environment configuration inputs and fully resolved runtime config, including a dedicated clientOptions public contract.
  • Reworks issuer authorization to use an atomic factory override object, and makes OcpClient runtime state properties explicit (T | undefined) instead of optional.
  • Adds exactOptionalPropertyTypes declaration/probe tests (source + built) and wires them into CI/linting.

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tsconfig.tests.json Excludes test/exact/** from the normal test TS project.
tsconfig.exact-public-config-tests.json Adds an exact-optional TS project used for public surface compile-time probes.
package.json Adds test:exact-public-config and runs it as part of test:declarations.
eslint.config.mjs Adds the new exact-public-config tsconfig to ESLint’s project list.
test/functions/issuerAuthorization/authorizeIssuer.test.ts Adds runtime tests ensuring malformed factory overrides fail before ledger access.
test/exact/sourcePublicConfig.types.ts Adds source-level .d.ts/type-shape probes for exact-optional public contracts.
test/exact/builtPublicConfig.types.ts Adds built (dist) public surface probes to ensure published types stay exact.
test/errors/errors.test.ts Strengthens error-shape expectations (explicit `
test/config/environment.test.ts Adds assertions for resolved discriminated auth state + Canton config conversion behavior.
test/client/OcpClient.test.ts Updates client authorization tests for atomic factory override + freezing semantics.
src/OcpClient.ts Splits options into clientOptions, makes runtime state explicit, freezes factory coords, and updates issuer authorization flow.
src/clientOptions.ts Introduces exported public client construction option types (deps, presets, env overrides, factory coords).
src/environment.ts Refactors configuration into input vs resolved discriminated unions; adds explicit resolved invariants.
src/index.ts Re-exports clientOptions from the package entrypoint.
src/observabilityTypes.ts Extracts observability-related type declarations into a dedicated module.
src/observability.ts Re-exports observability types from observabilityTypes while keeping implementation here.
src/functions/OpenCapTable/issuerAuthorization/types.ts Switches authorization params to atomic factory?: OcpFactoryCoordinates and updates observability type import.
src/functions/OpenCapTable/issuerAuthorization/authorizeIssuer.ts Updates authorization runtime validation and factory coordinate selection.
src/errors/OcpError.ts Makes cause/classification/context explicit `
src/errors/OcpContractError.ts Uses contextOrUndefined to omit empty context and makes metadata fields explicit `
src/errors/OcpNetworkError.ts Uses contextOrUndefined and makes endpoint/status explicit `
src/errors/OcpParseError.ts Uses contextOrUndefined and makes source explicit `
src/errors/OcpValidationError.ts Makes expectedType explicit `

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

Comment thread src/functions/OpenCapTable/issuerAuthorization/authorizeIssuer.ts Outdated
Comment thread src/OcpClient.ts Outdated
Comment thread src/errors/OcpValidationError.ts Outdated
@HardlyDifficult
HardlyDifficult marked this pull request as draft July 10, 2026 16:25
…e' into codex/exact-public-config-state

# Conflicts:
#	scripts/check-declarations.ts
#	src/functions/OpenCapTable/issuerAuthorization/types.ts
@HardlyDifficult
HardlyDifficult marked this pull request as ready for review July 10, 2026 18:09
@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

cursor review

@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

@copilot review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 567d4df. Configure here.

@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

@copilot review

Please confirm the exact current head 567d4df173837c8a29c62011a4b5aa5035b65025; CI and Cursor are green, while CodeRabbit remains externally rate-limited.

@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

@copilot review

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
src/OcpClient.ts (1)

1030-1047: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use dependencies.environment in this validation error.

validateInjectedEnvironment is only used on the injected-dependencies path, so this should report dependencies.environment to match the other validation errors and keep path-based filtering consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/OcpClient.ts` around lines 1030 - 1047, Update
validateInjectedEnvironment to use the validation path dependencies.environment
instead of environment when constructing OcpValidationError, while preserving
the existing network mismatch check and error details.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/functions/OpenCapTable/capTable/CapTableBatch.ts`:
- Around line 69-71: Update createUpdateCapTableCommandId to use
crypto.randomUUID() for the fallback command ID instead of combining Date.now()
with Math.random(), while preserving the existing update-captable prefix.

---

Outside diff comments:
In `@src/OcpClient.ts`:
- Around line 1030-1047: Update validateInjectedEnvironment to use the
validation path dependencies.environment instead of environment when
constructing OcpValidationError, while preserving the existing network mismatch
check and error details.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 257ed605-41d8-4a9f-932c-1db631805e2d

📥 Commits

Reviewing files that changed from the base of the PR and between 5f6b42e and 23ea54b.

📒 Files selected for processing (50)
  • eslint.config.mjs
  • package.json
  • scripts/check-declarations.ts
  • src/OcpClient.ts
  • src/clientOptions.ts
  • src/environment.ts
  • src/errors/OcpContractError.ts
  • src/errors/OcpError.ts
  • src/errors/OcpNetworkError.ts
  • src/errors/OcpParseError.ts
  • src/errors/OcpValidationError.ts
  • src/functions/OpenCapTable/capTable/CapTableBatch.ts
  • src/functions/OpenCapTable/capTable/archiveCapTable.ts
  • src/functions/OpenCapTable/capTable/buildCapTableCommand.ts
  • src/functions/OpenCapTable/factory/createFactory.ts
  • src/functions/OpenCapTable/issuerAuthorization/authorizeIssuer.ts
  • src/functions/OpenCapTable/issuerAuthorization/types.ts
  • src/functions/OpenCapTable/issuerAuthorization/withdrawAuthorization.ts
  • src/index.ts
  • src/observability.ts
  • src/observabilityTypes.ts
  • src/types/common.ts
  • src/utils/commandContext.ts
  • src/utils/commandParameters.ts
  • src/utils/environmentConfigKeys.ts
  • src/utils/exactObject.ts
  • src/utils/factoryCoordinates.ts
  • src/utils/observabilityConfig.ts
  • test/batch/CapTableBatch.test.ts
  • test/capTable/archiveCapTable.test.ts
  • test/client/OcpClient.test.ts
  • test/config/environment.test.ts
  • test/declarations/publicApi.types.ts
  • test/declarations/sourceClientConfig.types.ts
  • test/errors/errors.test.ts
  • test/exact/builtPublicConfig.types.ts
  • test/exact/sourcePublicConfig.types.ts
  • test/functions/factory/createFactory.test.ts
  • test/functions/issuerAuthorization/authorizeIssuer.test.ts
  • test/functions/issuerAuthorization/withdrawAuthorization.test.ts
  • test/mocks/fairmint-canton-node-sdk.ts
  • test/observability/observability.test.ts
  • test/publicApi/rootExports.test.ts
  • test/typeContracts/typeAssertions.ts
  • test/types/capTableBatch.types.ts
  • test/types/typeAssertions.types.ts
  • test/utils/factoryCoordinates.test.ts
  • test/validation/generatedDamlBoundary.test.ts
  • tsconfig.exact-public-config-tests.json
  • tsconfig.tests.json

Comment thread src/functions/OpenCapTable/capTable/CapTableBatch.ts
@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

Returned to draft: the fresh exact-head CodeRabbit full review identified a valid command-ID collision risk in the UpdateCapTable fallback. I am replacing the timestamp/Math.random() fallback with a cryptographic UUID, adding regression coverage, and will rerun all exact-head gates before requesting Copilot first again.

@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

@copilot review

Please review exact current head 84048b04c0b2aed9ed5fd382cf08979cc5a146fd. The fresh CodeRabbit collision finding is fixed, its thread is resolved, and CI plus OCP QuickStart are green. Please report any remaining actionable issue on this exact revision.

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown

@copilot review

Please review exact current head 84048b04c0b2aed9ed5fd382cf08979cc5a146fd. The fresh CodeRabbit collision finding is fixed, its thread is resolved, and CI plus OCP QuickStart are gr...

Reviewed exact head 84048b04c0b2aed9ed5fd382cf08979cc5a146fd against stacked base 5f6b42eb68416340a40c8bfa24eca4add64679ad. I do not see any remaining actionable issues for this exact revision.

I also re-checked required workflows in stacked order and both are green:

  • codex/exact-compensation-issuance (5f6b42e): CI and Test OCP CN-Quickstart Integration completed/success
  • codex/exact-public-config-state (84048b0): CI and Test OCP CN-Quickstart Integration completed/success

@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

@cursor review

Please review exact head 84048b04c0b2aed9ed5fd382cf08979cc5a146fd; Copilot has completed its exact-head review with no actionables.

@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

Please perform a fresh full review of exact head 84048b04c0b2aed9ed5fd382cf08979cc5a146fd against stacked base 5f6b42eb68416340a40c8bfa24eca4add64679ad. Copilot has completed first, CI and OCP QuickStart are green, and the prior command-ID thread is fixed and resolved.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026 •

Copy link
Copy Markdown

@HardlyDifficult Understood — triggering a fresh full review of exact head 84048b04c0b2aed9ed5fd382cf08979cc5a146fd against stacked base 5f6b42eb68416340a40c8bfa24eca4add64679ad, incorporating the noted context that Copilot has completed first, CI and OCP QuickStart are green, and the prior command-ID collision thread is fixed and resolved.

If adaptive rate limiting is still in effect for this attempt, that status will be reported once the action completes.

✅ Action performed

Full review finished.


You're currently rate limited under our Fair Usage Limits Policy. Your recent PR review activity is in the 95th percentile or higher among CodeRabbit users, so adaptive limits apply. Your next review will be available in 6 minutes.

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 84048b0. Configure here.

@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

Retry after the adaptive-limit window. Please perform a fresh full review of unchanged exact head 84048b04c0b2aed9ed5fd382cf08979cc5a146fd against stacked base 5f6b42eb68416340a40c8bfa24eca4add64679ad. Copilot reviewed this exact head first with no actionables, Cursor has now also reported no issues on this exact head, CI and OCP QuickStart are green, and all prior threads are resolved.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026 •

Copy link
Copy Markdown

@HardlyDifficult Understood — retrying the requested fresh full review of unchanged exact head 84048b04c0b2aed9ed5fd382cf08979cc5a146fd against stacked base 5f6b42eb68416340a40c8bfa24eca4add64679ad, incorporating the noted context that Copilot reviewed this exact head first with no actionables, Cursor has also reported no issues on this exact head, CI and OCP QuickStart are green, and all prior threads are resolved.

If adaptive rate limiting is still in effect for this attempt, that status will be reported once the action completes.

✅ Action performed

Full review finished.


You're currently rate limited under our Fair Usage Limits Policy. Your recent PR review activity is in the 95th percentile or higher among CodeRabbit users, so adaptive limits apply. Your next review will be available in 25 seconds.

@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

Retry after the reported 25-second adaptive-limit window. Please perform the fresh full review of unchanged exact head 84048b04c0b2aed9ed5fd382cf08979cc5a146fd against stacked base 5f6b42eb68416340a40c8bfa24eca4add64679ad. Copilot and Cursor completed exact-head no-findings reviews; CI and OCP QuickStart are green; all prior threads are resolved.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026 •

Copy link
Copy Markdown

@HardlyDifficult Understood — retrying the requested fresh full review of unchanged exact head 84048b04c0b2aed9ed5fd382cf08979cc5a146fd against stacked base 5f6b42eb68416340a40c8bfa24eca4add64679ad, incorporating the noted context that Copilot and Cursor have both completed exact-head reviews with no findings and that CI/OCP QuickStart remain green with all prior threads resolved.

If adaptive rate limiting is still in effect for this attempt, that status will be reported once the action completes.

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/functions/OpenCapTable/capTable/archiveCapTable.ts`:
- Around line 27-36: Widen the public CapTableContractDetails type used by
ArchiveCapTableParams to include contractId, createdEventBlob, and
synchronizerId, matching the fields accepted by snapshotCapTableContractDetails
and cross-checked against capTableContractId. Preserve templateId and make the
added fields’ optionality match the existing supported input shape.

In `@test/functions/issuerAuthorization/authorizeIssuer.test.ts`:
- Around line 1-225: Add a test in the authorizeIssuer factory configuration
suite covering an explicit factory: undefined value. Assert it rejects with the
expected validation error before ledger access, matching the existing
null/incomplete factory validation behavior.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 596a5ad2-027e-4ad5-bb9c-4ea545a4b840

📥 Commits

Reviewing files that changed from the base of the PR and between 5f6b42e and 84048b0.

📒 Files selected for processing (50)
  • eslint.config.mjs
  • package.json
  • scripts/check-declarations.ts
  • src/OcpClient.ts
  • src/clientOptions.ts
  • src/environment.ts
  • src/errors/OcpContractError.ts
  • src/errors/OcpError.ts
  • src/errors/OcpNetworkError.ts
  • src/errors/OcpParseError.ts
  • src/errors/OcpValidationError.ts
  • src/functions/OpenCapTable/capTable/CapTableBatch.ts
  • src/functions/OpenCapTable/capTable/archiveCapTable.ts
  • src/functions/OpenCapTable/capTable/buildCapTableCommand.ts
  • src/functions/OpenCapTable/factory/createFactory.ts
  • src/functions/OpenCapTable/issuerAuthorization/authorizeIssuer.ts
  • src/functions/OpenCapTable/issuerAuthorization/types.ts
  • src/functions/OpenCapTable/issuerAuthorization/withdrawAuthorization.ts
  • src/index.ts
  • src/observability.ts
  • src/observabilityTypes.ts
  • src/types/common.ts
  • src/utils/commandContext.ts
  • src/utils/commandParameters.ts
  • src/utils/environmentConfigKeys.ts
  • src/utils/exactObject.ts
  • src/utils/factoryCoordinates.ts
  • src/utils/observabilityConfig.ts
  • test/batch/CapTableBatch.test.ts
  • test/capTable/archiveCapTable.test.ts
  • test/client/OcpClient.test.ts
  • test/config/environment.test.ts
  • test/declarations/publicApi.types.ts
  • test/declarations/sourceClientConfig.types.ts
  • test/errors/errors.test.ts
  • test/exact/builtPublicConfig.types.ts
  • test/exact/sourcePublicConfig.types.ts
  • test/functions/factory/createFactory.test.ts
  • test/functions/issuerAuthorization/authorizeIssuer.test.ts
  • test/functions/issuerAuthorization/withdrawAuthorization.test.ts
  • test/mocks/fairmint-canton-node-sdk.ts
  • test/observability/observability.test.ts
  • test/publicApi/rootExports.test.ts
  • test/typeContracts/typeAssertions.ts
  • test/types/capTableBatch.types.ts
  • test/types/typeAssertions.types.ts
  • test/utils/factoryCoordinates.test.ts
  • test/validation/generatedDamlBoundary.test.ts
  • tsconfig.exact-public-config-tests.json
  • tsconfig.tests.json

Comment thread src/functions/OpenCapTable/capTable/archiveCapTable.ts
Comment thread test/functions/issuerAuthorization/authorizeIssuer.test.ts
@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

Returned to draft: the fresh exact-head CodeRabbit full review found two valid gaps. I am widening the public cap-table contract-details type to match the already-supported disclosure fields and adding low-level factory: undefined pre-ledger regression coverage. Exact-head CI and the Copilot-first reviewer sequence will be rerun after the material fix.

@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

Review follow-up pushed at exact head ce66710d5d98380c9a480a6bfdbff70f4f37e1c0. The public cap-table disclosure type now matches all runtime-supported fields, and direct authorizeIssuer explicitly covers present-but-undefined factory rejection before ledger access. Both CodeRabbit threads are answered and resolved. Local full coverage (74 suites / 4,079 tests), clean build, declaration gates, lint, formatting, package dry-run, and diff check pass. The PR remains draft while exact-head hosted CI and QuickStart run; Copilot will be requested first after those gates pass.

Copilot AI 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.

Pull request overview

Copilot reviewed 50 out of 50 changed files in this pull request and generated 1 comment.

Comment thread src/utils/observabilityConfig.ts

Copilot AI 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.

Pull request overview

Copilot reviewed 50 out of 50 changed files in this pull request and generated 2 comments.

Comment thread src/functions/OpenCapTable/issuerAuthorization/authorizeIssuer.ts
Comment thread src/utils/factoryCoordinates.ts

Copilot AI 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.

Pull request overview

Copilot reviewed 50 out of 50 changed files in this pull request and generated 1 comment.

Comment thread src/utils/commandContext.ts

Copilot AI 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.

Pull request overview

Copilot reviewed 50 out of 50 changed files in this pull request and generated no new comments.

@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

@cursor review

Please review exact current head 92875cff4fe7a1e6d79b976c445b00c279220a3b after Copilot completed its required exact-head 50/50-file review with no new comments: #417 (review). Both required hosted checks remain successful, GitHub reports CLEAN/MERGEABLE, and there are zero unresolved threads. Focus on the exact public configuration boundary, explicit-undefined semantics, detached one-read snapshots, and diagnostic/code consistency. Report every actionable current-head issue.

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 92875cf. Configure here.

@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

Please perform a substantive fresh full review of unchanged exact head 92875cff4fe7a1e6d79b976c445b00c279220a3b against stacked base 5f6b42eb68416340a40c8bfa24eca4add64679ad. Copilot reviewed all 50 changed files on this exact head with no new comments, Cursor Bugbot found no issues on this exact head, both required hosted checks remain successful, GitHub reports CLEAN/MERGEABLE, and all prior review threads are resolved. Please report every actionable current-head issue, including anything involving exact optional-property semantics, detached snapshot behavior, or validation diagnostic consistency.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026 •

Copy link
Copy Markdown

@HardlyDifficult Understood — triggering a fresh full review of unchanged exact head 92875cff4fe7a1e6d79b976c445b00c279220a3b against stacked base 5f6b42eb68416340a40c8bfa24eca4add64679ad, incorporating the noted context that Copilot reviewed all 50 changed files with no new comments, Cursor Bugbot found no issues, both required hosted checks remain successful, GitHub reports CLEAN/MERGEABLE, and all prior review threads are resolved. I'll focus on exact optional-property semantics, detached snapshot behavior, and validation diagnostic consistency, and report every actionable finding or an explicit no-findings result.

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/errors/OcpError.ts`:
- Around line 7-11: Consolidate the repeated diagnostic-context handling by
adding a shared helper alongside contextOrUndefined that merges context and
produces the optional details spread. Update OcpParseError, OcpNetworkError, and
OcpContractError to use this helper instead of independently calling
mergeDiagnosticContext, contextOrUndefined, and conditionally spreading context,
while preserving their existing super(...) details.

In `@src/functions/OpenCapTable/capTable/CapTableBatch.ts`:
- Around line 74-93: Extract the shared native-error/proxy detection from
safeBatchFailureMessage and safeBatchFailureCause into a
resolveNativeError(error): Error | undefined helper. Update both functions to
reuse this helper while preserving their existing message extraction and
fallback behavior, ensuring both consistently identify safe native errors.

In `@src/utils/commandContext.ts`:
- Around line 40-52: Consolidate the explicit-undefined validation in
optionalValue with the existing optionalCommandParameter/explicitUndefined logic
from commandParameters.ts, reusing the shared validation path and
toExactDataValidationError conventions. Remove the duplicated OcpValidationError
construction while preserving rejection of present-but-undefined values and
consistent error text and behavior across both paths.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 6e233608-8423-4f43-9228-e11f85eea49f

📥 Commits

Reviewing files that changed from the base of the PR and between 5f6b42e and 92875cf.

📒 Files selected for processing (50)
  • eslint.config.mjs
  • package.json
  • scripts/check-declarations.ts
  • src/OcpClient.ts
  • src/clientOptions.ts
  • src/environment.ts
  • src/errors/OcpContractError.ts
  • src/errors/OcpError.ts
  • src/errors/OcpNetworkError.ts
  • src/errors/OcpParseError.ts
  • src/errors/OcpValidationError.ts
  • src/functions/OpenCapTable/capTable/CapTableBatch.ts
  • src/functions/OpenCapTable/capTable/archiveCapTable.ts
  • src/functions/OpenCapTable/capTable/buildCapTableCommand.ts
  • src/functions/OpenCapTable/factory/createFactory.ts
  • src/functions/OpenCapTable/issuerAuthorization/authorizeIssuer.ts
  • src/functions/OpenCapTable/issuerAuthorization/types.ts
  • src/functions/OpenCapTable/issuerAuthorization/withdrawAuthorization.ts
  • src/index.ts
  • src/observability.ts
  • src/observabilityTypes.ts
  • src/types/common.ts
  • src/utils/commandContext.ts
  • src/utils/commandParameters.ts
  • src/utils/environmentConfigKeys.ts
  • src/utils/exactObject.ts
  • src/utils/factoryCoordinates.ts
  • src/utils/observabilityConfig.ts
  • test/batch/CapTableBatch.test.ts
  • test/capTable/archiveCapTable.test.ts
  • test/client/OcpClient.test.ts
  • test/config/environment.test.ts
  • test/declarations/publicApi.types.ts
  • test/declarations/sourceClientConfig.types.ts
  • test/errors/errors.test.ts
  • test/exact/builtPublicConfig.types.ts
  • test/exact/sourcePublicConfig.types.ts
  • test/functions/factory/createFactory.test.ts
  • test/functions/issuerAuthorization/authorizeIssuer.test.ts
  • test/functions/issuerAuthorization/withdrawAuthorization.test.ts
  • test/mocks/fairmint-canton-node-sdk.ts
  • test/observability/observability.test.ts
  • test/publicApi/rootExports.test.ts
  • test/typeContracts/typeAssertions.ts
  • test/types/capTableBatch.types.ts
  • test/types/typeAssertions.types.ts
  • test/utils/factoryCoordinates.test.ts
  • test/validation/generatedDamlBoundary.test.ts
  • tsconfig.exact-public-config-tests.json
  • tsconfig.tests.json

Comment thread src/errors/OcpError.ts
Comment on lines +7 to +11
/** @internal */
export function contextOrUndefined(context: OcpErrorContext): OcpErrorContext | undefined {
return Object.keys(context).length === 0 ? undefined : context;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider consolidating the repeated "conditional context spread" boilerplate.

OcpParseError, OcpNetworkError, and OcpContractError all now repeat the identical pattern: compute context via mergeDiagnosticContext + contextOrUndefined, then conditionally spread { context } into the super(...) details. Centralizing this here alongside contextOrUndefined would remove the triplicated glue code and give a single place to change the pattern later.

♻️ Proposed consolidating helper
 /** `@internal` */
 export function contextOrUndefined(context: OcpErrorContext): OcpErrorContext | undefined {
   return Object.keys(context).length === 0 ? undefined : context;
 }
+
+/** `@internal` */
+export function buildErrorDetails(
+  classification: string,
+  context: OcpErrorContext
+): OcpErrorDetails {
+  const resolvedContext = contextOrUndefined(context);
+  return {
+    classification,
+    ...(resolvedContext !== undefined ? { context: resolvedContext } : {}),
+  };
+}

Then each subclass (e.g. OcpNetworkError) simplifies to:

-    const context = contextOrUndefined(
-      mergeDiagnosticContext(options?.context, { endpoint, statusCode: options?.statusCode })
-    );
-    super(message, code, options?.cause, {
-      classification: options?.classification ?? 'network_error',
-      ...(context !== undefined ? { context } : {}),
-    });
+    super(message, code, options?.cause, buildErrorDetails(
+      options?.classification ?? 'network_error',
+      mergeDiagnosticContext(options?.context, { endpoint, statusCode: options?.statusCode })
+    ));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/** @internal */
export function contextOrUndefined(context: OcpErrorContext): OcpErrorContext | undefined {
return Object.keys(context).length === 0 ? undefined : context;
}
/** `@internal` */
export function contextOrUndefined(context: OcpErrorContext): OcpErrorContext | undefined {
return Object.keys(context).length === 0 ? undefined : context;
}
/** `@internal` */
export function buildErrorDetails(
classification: string,
context: OcpErrorContext
): OcpErrorDetails {
const resolvedContext = contextOrUndefined(context);
return {
classification,
...(resolvedContext !== undefined ? { context: resolvedContext } : {}),
};
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/errors/OcpError.ts` around lines 7 - 11, Consolidate the repeated
diagnostic-context handling by adding a shared helper alongside
contextOrUndefined that merges context and produces the optional details spread.
Update OcpParseError, OcpNetworkError, and OcpContractError to use this helper
instead of independently calling mergeDiagnosticContext, contextOrUndefined, and
conditionally spreading context, while preserving their existing super(...)
details.

Comment on lines +74 to 93
function safeBatchFailureMessage(error: unknown): string {
const objectLike = (typeof error === 'object' && error !== null) || typeof error === 'function';
if (objectLike && !nodeUtilTypes.isProxy(error) && nodeUtilTypes.isNativeError(error)) {
try {
const descriptor = Object.getOwnPropertyDescriptor(error, 'message');
if (descriptor !== undefined && 'value' in descriptor && typeof descriptor.value === 'string') {
return toSafeDiagnosticText(descriptor.value);
}
} catch {
// Fall through to the bounded descriptor-safe diagnostic representation.
}
}
return toSafeDiagnosticText(error);
}

function safeBatchFailureCause(error: unknown): Error {
const objectLike = (typeof error === 'object' && error !== null) || typeof error === 'function';
if (objectLike && !nodeUtilTypes.isProxy(error) && nodeUtilTypes.isNativeError(error)) return error;
return new Error(toSafeDiagnosticText(error));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated native-error/proxy detection between safeBatchFailureMessage and safeBatchFailureCause.

Both helpers independently recompute the same objectLike && !isProxy && isNativeError condition. Extracting a shared resolveNativeError(error): Error | undefined helper would remove the duplication and guarantee both functions always agree on what counts as a "safe" native error.

♻️ Suggested consolidation
+function resolveNativeError(error: unknown): Error | undefined {
+  const objectLike = (typeof error === 'object' && error !== null) || typeof error === 'function';
+  if (objectLike && !nodeUtilTypes.isProxy(error) && nodeUtilTypes.isNativeError(error)) return error;
+  return undefined;
+}
+
 function safeBatchFailureMessage(error: unknown): string {
-  const objectLike = (typeof error === 'object' && error !== null) || typeof error === 'function';
-  if (objectLike && !nodeUtilTypes.isProxy(error) && nodeUtilTypes.isNativeError(error)) {
+  const nativeError = resolveNativeError(error);
+  if (nativeError !== undefined) {
     try {
-      const descriptor = Object.getOwnPropertyDescriptor(error, 'message');
+      const descriptor = Object.getOwnPropertyDescriptor(nativeError, 'message');
       if (descriptor !== undefined && 'value' in descriptor && typeof descriptor.value === 'string') {
         return toSafeDiagnosticText(descriptor.value);
       }
     } catch {
       // Fall through to the bounded descriptor-safe diagnostic representation.
     }
   }
   return toSafeDiagnosticText(error);
 }

 function safeBatchFailureCause(error: unknown): Error {
-  const objectLike = (typeof error === 'object' && error !== null) || typeof error === 'function';
-  if (objectLike && !nodeUtilTypes.isProxy(error) && nodeUtilTypes.isNativeError(error)) return error;
-  return new Error(toSafeDiagnosticText(error));
+  return resolveNativeError(error) ?? new Error(toSafeDiagnosticText(error));
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function safeBatchFailureMessage(error: unknown): string {
const objectLike = (typeof error === 'object' && error !== null) || typeof error === 'function';
if (objectLike && !nodeUtilTypes.isProxy(error) && nodeUtilTypes.isNativeError(error)) {
try {
const descriptor = Object.getOwnPropertyDescriptor(error, 'message');
if (descriptor !== undefined && 'value' in descriptor && typeof descriptor.value === 'string') {
return toSafeDiagnosticText(descriptor.value);
}
} catch {
// Fall through to the bounded descriptor-safe diagnostic representation.
}
}
return toSafeDiagnosticText(error);
}
function safeBatchFailureCause(error: unknown): Error {
const objectLike = (typeof error === 'object' && error !== null) || typeof error === 'function';
if (objectLike && !nodeUtilTypes.isProxy(error) && nodeUtilTypes.isNativeError(error)) return error;
return new Error(toSafeDiagnosticText(error));
}
function resolveNativeError(error: unknown): Error | undefined {
const objectLike = (typeof error === 'object' && error !== null) || typeof error === 'function';
if (objectLike && !nodeUtilTypes.isProxy(error) && nodeUtilTypes.isNativeError(error)) return error;
return undefined;
}
function safeBatchFailureMessage(error: unknown): string {
const nativeError = resolveNativeError(error);
if (nativeError !== undefined) {
try {
const descriptor = Object.getOwnPropertyDescriptor(nativeError, 'message');
if (descriptor !== undefined && 'value' in descriptor && typeof descriptor.value === 'string') {
return toSafeDiagnosticText(descriptor.value);
}
} catch {
// Fall through to the bounded descriptor-safe diagnostic representation.
}
}
return toSafeDiagnosticText(error);
}
function safeBatchFailureCause(error: unknown): Error {
return resolveNativeError(error) ?? new Error(toSafeDiagnosticText(error));
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/functions/OpenCapTable/capTable/CapTableBatch.ts` around lines 74 - 93,
Extract the shared native-error/proxy detection from safeBatchFailureMessage and
safeBatchFailureCause into a resolveNativeError(error): Error | undefined
helper. Update both functions to reuse this helper while preserving their
existing message extraction and fallback behavior, ensuring both consistently
identify safe native errors.

Comment on lines +40 to +52
function optionalValue(snapshot: ExactObjectSnapshot, key: string, root: string): unknown {
if (!snapshot.has(key)) {
return undefined;
}
const value = snapshot.get(key);
if (value === undefined) {
throw new OcpValidationError(`${root}.${key}`, `${key} must be omitted rather than set to undefined.`, {
code: OcpErrorCodes.INVALID_TYPE,
expectedType: 'defined value or omitted property',
});
}
return value;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate "must be omitted rather than undefined" validation logic.

optionalValue here reimplements the same explicit-undefined rejection already present as optionalCommandParameter/explicitUndefined in commandParameters.ts (per graph context). Given the prior consolidation of ExactDataFailure→OcpValidationError mapping into toExactDataValidationError, this analogous "value present but undefined" check is a good candidate for the same treatment to keep error text/behavior from diverging between command-context and command-parameter paths.

♻️ Suggested consolidation
-function optionalValue(snapshot: ExactObjectSnapshot, key: string, root: string): unknown {
-  if (!snapshot.has(key)) {
-    return undefined;
-  }
-  const value = snapshot.get(key);
-  if (value === undefined) {
-    throw new OcpValidationError(`${root}.${key}`, `${key} must be omitted rather than set to undefined.`, {
-      code: OcpErrorCodes.INVALID_TYPE,
-      expectedType: 'defined value or omitted property',
-    });
-  }
-  return value;
-}
+import { optionalCommandParameter } from './commandParameters';
+const optionalValue = optionalCommandParameter;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/commandContext.ts` around lines 40 - 52, Consolidate the
explicit-undefined validation in optionalValue with the existing
optionalCommandParameter/explicitUndefined logic from commandParameters.ts,
reusing the shared validation path and toExactDataValidationError conventions.
Remove the duplicated OcpValidationError construction while preserving rejection
of present-but-undefined values and consistent error text and behavior across
both paths.

@HardlyDifficult

Copy link
Copy Markdown
Collaborator Author

Readiness retracted for the DAML-validation boundary cleanup. This PR will retain SDK-owned auth, environment, configuration, and command-context guarantees while removing abandoned stacked ancestry, then be revalidated and freshly reviewed on its exact resulting head before merge.

This branch has not been deployed

No deployments
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