ALL-1874 PR-2: Backend — testRule mutation and multi-transform rule chaining
queued## Context
Linear issue ALL-1874. Depends on PR-1 (fleet-task fd8033e5) landing first — the new matcher/transform types must be available before this PR.
## Key files
- `domains/identity/src/services/staging/ruleEngine.ts` — applyTransform(), evaluateRules(); chaining changes here
- `domains/identity/src/services/staging/resolutionRuleService.ts` — CreateResolutionRuleSchema, UpdateResolutionRuleSchema; transform field changes to array
- `domains/identity/src/graphql/typeDefs.graphql` — add testRule query and update transform type comment
- `domains/identity/src/graphql/resolvers/staging/ruleQueries.ts` — add testRule resolver
- `domains/identity/prisma/schema.prisma` — ResolutionRule.transform is already Json; no schema change needed (array JSON is valid)
## Changes required
### 1. Multi-transform chaining
- Change TransformSchema in resolutionRuleService.ts and ruleEngine.ts to accept EITHER a single TransformDef OR an array TransformDef[]
- Use `z.union([TransformSchema, z.array(TransformSchema)])` in both CreateResolutionRuleSchema and UpdateResolutionRuleSchema
- In applyTransform(), accept `transform: TransformDef | TransformDef[]` and iterate if array
- In evaluateRules(), accumulate all beforeAfter entries across the chain
- Backward compatible: existing single-transform rules (stored as plain JSON object) still parse and fire correctly
### 2. testRule query
Add to typeDefs.graphql:
```graphql
type TestRuleResult {
matched: Boolean!
before: JSON
after: JSON
confidence: Float
transformsApplied: Int
}
input TestRuleInput {
issueType: String!
field: String
matcher: JSON!
transform: JSON! # single or array
sampleRecord: JSON! # { normalizedData: { ... } }
}
extend type Query {
testRule(input: TestRuleInput!): TestRuleResult! @requireClientOrUserAuthentication
}
```
Resolver in ruleQueries.ts: build an in-memory ResolutionRule-like object, call parseMatcher/parseTransform from ruleEngine, call applyTransform with the sample record, return matched/before/after without persisting. No DB write.
## Acceptance test
- `pnpm --filter identity typecheck` passes
- `pnpm --filter identity test ruleEngine` passes with a test that chains two transforms on the same record
- testRule resolver returns correct before/after for a sample `{ normalizedData: { postalCode: "1234" } }` input
## Notes
- Depends on PR-1 (new matcher/transform types)
- The SDL mutation addendum is minimal; no new Prisma migration needed
- Rule cascading (rules triggering other rules) is scoped out of this issue — too complex for initial release
Event Timeline
created