Skip to content

[2.x] Add validator rules for spec 2.0.0-rc.2 - #1226

Merged
lorisleiva merged 1 commit into
mainfrom
10-13-add_validator_rules_for_spec_2.0.0-rc.2
Oct 13, 2026
Merged

lorisleiva merged 1 commit into
mainfrom
10-13-add_validator_rules_for_spec_2.0.0-rc.2

Conversation

@lorisleiva

@lorisleiva lorisleiva commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

This PR adds validator rules for the features of spec 2.0.0-rc.2, and the helpers they share with the rest of Codama.

parseInterpolatedIntent('Mint ${data.amount} (${accounts.mint.data.decimals})');
// ['Mint ', dataValueNode('amount'), ' (', accountDataValueNode('mint', { path: 'decimals' }), ')']
  • Interpolated intents: parseInterpolatedIntent and printInterpolatedIntent turn placeholders into the contextual value nodes they are equivalent to, and back. Invalid placeholders throw CODAMA_ERROR__INVALID_INTERPOLATED_INTENT_PLACEHOLDER.
  • Paths: resolveTypePath can follow account links with followAccountLinks, and isValueNodeOfType checks a value against a type structurally.
  • Validators: new rules check ticks per second and fixed-point scales, value labels, field discriminator paths (which must not cross account links), account links, and the paths and accounts of data values, account data values and intent placeholders.
  • Renames: renaming accounts and fields now also repoints ${accounts.x.data…} placeholders.

@changeset-bot

changeset-bot Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 157675b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@lorisleiva lorisleiva changed the title Add validator rules for spec 2.0.0-rc.2 [2.x] Add validator rules for spec 2.0.0-rc.2 Oct 13, 2026

Copy link
Copy Markdown
Member Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@lorisleiva

Copy link
Copy Markdown
Member Author

@trevor-cortex

@trevor-cortex trevor-cortex 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.

Summary

Adds the validator rules for spec 2.0.0-rc.2 plus the shared helpers they need:

  • parseInterpolatedIntent / printInterpolatedIntent in @codama/nodes, turning ${data.…} / ${accounts.x} / ${accounts.x.data…} placeholders into the contextual value nodes they denote (and back), with a new CODAMA_ERROR__INVALID_INTERPOLATED_INTENT_PLACEHOLDER for anything off-grammar.
  • resolveTypePath gains followAccountLinks, and isValueNodeOfType checks a concrete value against a type structurally (following defined-type links, detecting alias cycles).
  • New validation items: ticks-per-second, fixed-point scale, value labels (concrete + type-matching), field discriminator paths (must land on a struct field, must not cross account links), missing account links, and the account/path checks for dataValueNode, accountDataValueNode and intent placeholders via a shared getContextualValueItems.
  • The rename transformers in updateHelpers are refactored into renameAccountValue / renameDataValue / renameAccountDataValue, which are reused to repoint intent placeholders — including ${accounts.x.data.field}, which the old regex didn't handle.

The code is clean and the test coverage is thorough; I traced the parser grammar, the account-link following, and the dedupe logic against the resolver and they hold up. Two things worth a look before merging:

Watch out for

  1. Double-reporting gap for accountDataValueNode defaults. The PR dedupes INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY only when the dependency is a dataValueNode. But getDependencies() turns an accountDataValueNode('mint', …) into a synthesized accountValueNode('mint'), so an account default like conditionalValueNode({ condition: accountDataValueNode('mint', { path: 'decimals' }), … }) with no mint account gets reported twice: once by the resolver ("invalid dependency") and once by visitAccountDataValue ("Account "mint" is not an account of instruction…"). See the inline comment for a suggested approach.

  2. accountValueNode has no contextual check. getContextualValueItems handles accountValueNode (used for intent placeholders), but there's no visitAccountValue, so providedNode('x', accountValueNode('missing')) that is never injected into a default goes unreported, while the same node in an intent is reported. Adding visitAccountValue would close that and also make the dedupe in (1) uniform: "skip the resolver error whenever the dependency reports itself".

Minor / optional

  • isValueNodeOfType for enumTypeNode matches on value.variant only; value.enum (the link on the value node) isn't checked against the type being matched. Given the doc says "structural", that's probably intended, but worth a line in the docblock so nobody files it as a bug.
  • FixedPointTypeNode.scale is documented as "must be non-zero" while the validator requires a positive integer. Likely the spec intends positive — just flagging the wording mismatch in case the spec text should be tightened.
  • No changeset in the PR. Per CONTRIBUTING.md user-facing changes need one — unless rc work on this branch rolls into the seeded major changeset, in which case ignore.

Notes for other reviewers

  • The followedAccounts cycle guard in resolveContainer is per-segment by design: next.next.value on a self-linking list legitimately re-follows the same account; only an account whose data is itself a self-linking public key (no type to apply the segment to) throws. The tests cover both.
  • visitInjectedValue now treats valueLabelDisplayNode as a nesting ancestor so injected labels are reported once (by visitValueLabelDisplay) rather than as an unprovided injection — intentional.
  • Intent renaming returns the original string when no part changed, so formatting is only normalised through printInterpolatedIntent when a rename actually occurred; the parse→print round-trip is tested as identity for valid templates.

Comment thread packages/validators/src/getValidationItemsVisitor.ts Outdated
Comment thread packages/validators/src/getValidationItemsVisitor.ts Outdated
@lorisleiva
lorisleiva force-pushed the 10-13-add_validator_rules_for_spec_2.0.0-rc.2 branch from af8dcb4 to 824a1b4 Compare October 13, 2026 12:37

@trevor-cortex trevor-cortex 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.

Re-review

Both points from the first pass are addressed:

  • visitAccountValue is in, and visitAccountBumpValue checks the bump's account the same way — so bump values pointing at unknown accounts (including inside PDA seeds, which the resolver never tracked) are now reported.
  • The resolver dedupe is now uniform: the INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY error is skipped whenever getContextualValueItems would report the dependency itself. Covered by the new "account data value defaults of unknown accounts once" test.
  • isValueNodeOfType docblock now states the enum link isn't compared, and the visitFieldDiscriminator early return is in.

I re-traced the dedupe against getResolvedInstructionInputsVisitor.getDependencies / resolveDependencies and it holds for all the self-contained cases: accountValueNode, accountBumpValueNode, accountDataValueNode (synthesized to accountValueNode), dataValueNode, PDA seeds and conditionals. The cases where resolveTypePath succeeds but findFieldByPath doesn't (tuple data with [0], or a linked data type with no program in the path) still fall through to the resolver error, which is the right fallback.

One edge case worth a decision (inline): a dependency that comes from a parent instruction's provides is checked against the parent's accounts by visitAccountValue/visitDataValue, but the resolver checks it against the sub-instruction's. If it's valid in the parent and invalid in the sub-instruction, the new dedupe drops the resolver error and nothing else reports it. Not blocking — it's a corner of the provides/sub-instruction model — but it's a silent regression versus the previous behaviour, so worth either guarding or documenting.

Still open from last time, both minor: FixedPointTypeNode.scale doc says "non-zero" while the validator requires positive; and no changeset (ignore if rc work rolls into the seeded major one).

Approving — the remaining point is a judgement call rather than a correctness issue in the common path.

Comment thread packages/validators/src/getValidationItemsVisitor.ts
@lorisleiva
lorisleiva force-pushed the 10-13-add_validator_rules_for_spec_2.0.0-rc.2 branch from 824a1b4 to 157675b Compare October 13, 2026 12:58
@lorisleiva
lorisleiva merged commit 7b2f15f into main Oct 13, 2026
3 of 5 checks passed
@lorisleiva
lorisleiva deleted the 10-13-add_validator_rules_for_spec_2.0.0-rc.2 branch October 13, 2026 13:00
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.

2 participants