Skip to content

feat(schema): add data_class, expressions field, and mutual exclusivity#11

Open
albertgwo wants to merge 3 commits intomainfrom
feat/engine-pr0c-schema-additions
Open

feat(schema): add data_class, expressions field, and mutual exclusivity#11
albertgwo wants to merge 3 commits intomainfrom
feat/engine-pr0c-schema-additions

Conversation

@albertgwo
Copy link
Copy Markdown
Contributor

@albertgwo albertgwo commented Mar 19, 2026

User description

Summary

  • Add data_class enum (public, internal, confidential, restricted) to node metadata
  • Add expressions field for labeled expression definitions on action nodes
  • Add mutual exclusivity validation (next vs cases, next vs branches)
  • Regenerate TypeScript types from updated JSON Schema

Dependency

Base: main (independent of PR 0a, 0b)

PR 3 of 16 in the execution engine implementation.

Test plan

  • Schema validates data_class enum values
  • Schema validates expressions field structure
  • Mutual exclusivity errors for conflicting node fields
  • TypeScript types match updated JSON Schema

Generated description

Below is a concise technical summary of the changes proposed in this PR:
Extend the flowprint schema to track data_class labels across lanes and nodes, ensuring serialization ordering and generated types reflect the new metadata. Regenerate validation, serialization, and tests so action nodes can expose expressions while enforcing their mutual exclusivity with rules/entry_points.

TopicDetails
Action expressions Validate action expressions alongside their serialization ordering and enforce mutual exclusivity with rules/entry_points, covering the schema, validator, and tests.
Modified files (4)
  • packages/schema/flowprint.schema.json
  • packages/schema/src/__tests__/data-class-expressions.test.ts
  • packages/schema/src/serialize.ts
  • packages/schema/src/structural.ts
Latest Contributors(1)
UserCommitDate
albertgwo@gmail.comfeat-complete-the-loop...March 02, 2026
Data classification Add data_class metadata to lanes and nodes, updating the schema, serializer ordering, generated types, and regression tests to preserve the new enum-driven labels in YAML output.
Modified files (4)
  • packages/schema/flowprint.schema.json
  • packages/schema/src/__tests__/data-class-expressions.test.ts
  • packages/schema/src/serialize.ts
  • packages/schema/src/types.generated.ts
Latest Contributors(1)
UserCommitDate
albertgwo@gmail.comfeat-complete-the-loop...March 02, 2026
This pull request is reviewed by Baz. Review like a pro on (Baz).

…ty validation

Add data_class array (pii, financial, credentials, internal) to all
node types and lanes for trace redaction policy. Add expressions
object to action nodes for engine-native transforms. Enforce mutual
exclusivity: action nodes cannot have more than one of expressions,
rules, or entry_points.

Update serializer key ordering for deterministic output and add
dedicated lane serializer to handle data_class arrays.
…sivity

Cover schema validation, structural validation, serialization round-trips,
and key ordering for the new data_class and expressions fields.
23 new test cases across validation and serialization.
Comment on lines 157 to 168
* Markdown notes for documentation and design rationale
*/
notes?: string;
/**
* Data classification labels for trace redaction policy
*/
data_class?: ("pii" | "financial" | "credentials" | "internal")[];
metadata?: {
[k: string]: string;
};
entry_points?: EntryPoint[];
rules?: RulesRef;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

validateExpressions ignores node.expressions, should we treat it like node.inputs, call validateSingleExpression for each value, and verify structural.ts/serialize.ts consistency?

Finding type: Logical Bugs | Severity: 🔴 High


Want Baz to fix this for you? Activate Fixer

Other fix methods

Fix in Cursor

Prompt for AI Agents:

In packages/engine/src/expressions/validator.ts around lines 157-175, the
validateExpressions logic does not handle the new ActionNode.expressions property, so
expression syntax in that map is not being validated. Update the validator to treat
node.expressions like node.inputs: if node.expressions is present, iterate over its
key/value pairs and call validateSingleExpression (or the existing per-expression
validation helper) for each value, attaching the same error context used for inputs.
After that, run a quick review of packages/schema/src/structural.ts and
packages/schema/src/serialize.ts to confirm those files’ mutual-exclusion checks and
serialization order remain consistent with the validator change and adjust any error
messages or ordering if necessary.

Heads up!

Your free trial ends tomorrow.
To keep getting your PRs reviewed by Baz, update your team's subscription

Comment on lines +117 to +121
"data_class": {
"type": "array",
"items": {
"type": "string",
"enum": ["pii", "financial", "credentials", "internal"]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The new data_class definition (lines 117‑124) is copied verbatim across every lane and node schema entry (lanes, action, switch, parallel, wait, etc.). That is the same non-trivial property shape repeated at lines 212‑219, 293‑300, 367‑374, 430‑437, 508‑515, 558‑565, 606‑613, and so on. If we ever need to tweak the enum or description (or add constraints), every copy has to be updated in lockstep. Can we move this to a single shared schema definition (e.g. #/definitions/DataClassLabels and $ref it in each object) so the constraint lives in one place and serialization/validation changes stay consistent?

Finding type: Code Dedup and Conventions | Severity: 🟢 Low


Want Baz to fix this for you? Activate Fixer

Heads up!

Your free trial ends tomorrow.
To keep getting your PRs reviewed by Baz, update your team's subscription

Comment on lines +117 to +124
"data_class": {
"type": "array",
"items": {
"type": "string",
"enum": ["pii", "financial", "credentials", "internal"]
},
"description": "Data classification labels for trace redaction policy"
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

packages/schema adds data_class and expressions but doesn't include a .changeset/*.md — should we add one describing those additions?

Finding type: AI Coding Guidelines | Severity: 🟠 Medium


Want Baz to fix this for you? Activate Fixer

Other fix methods

Fix in Cursor

Prompt for AI Agents:

In packages/schema/flowprint.schema.json around lines 117-124, the new "data_class"
array (and similarly the new "expressions" property elsewhere) constitutes a
package-level API change for packages/schema but no .changeset/*.md entry was added.
Create a new .changeset markdown file describing the addition of the data_class field
and expressions (brief summary, type of change: minor or patch per repo policy), list
the affected files (packages/schema/flowprint.schema.json,
packages/schema/src/serialize.ts, packages/schema/src/structural.ts,
packages/schema/src/types.generated.ts, and
packages/schema/src/__tests__/data-class-expressions.test.ts), and ensure the changeset
follows the repository's CLAUDE.md format so release tooling will pick it up. If your
repo requires updating package.json version or changelog metadata in the changeset,
include that as well.

Heads up!

Your free trial ends tomorrow.
To keep getting your PRs reviewed by Baz, update your team's subscription

Comment on lines +44 to +55
// Mutual exclusion: expressions vs rules vs entry_points on action nodes
if (type === 'action') {
const hasRules = node.rules !== undefined
const hasEntryPoints = node.entry_points !== undefined
const hasExpressions = node.expressions !== undefined

if (hasExpressions && hasRules) {
errors.push({
path: `/nodes/${nodeId}`,
message: 'Action node cannot have both "expressions" and "rules". Use one or the other',
severity: '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.

Should we update packages/engine/src/expressions/validator.ts to allow zero entry_points when expressions are present and sync structural.ts mutual-exclusion logic with the schema that now permits expressions-only action nodes?

Finding type: Logical Bugs | Severity: 🔴 High


Want Baz to fix this for you? Activate Fixer

Other fix methods

Fix in Cursor

Prompt for AI Agents:

In packages/schema/src/structural.ts around lines 44 to 72 in the validateStructure
function (the mutual-exclusion checks for action nodes), confirm that action nodes are
allowed to have expressions-only (no entry_points) and keep the current mutual-exclusion
errors for pairs of expressions/rules/entry_points. Then update the engine validator in
packages/engine/src/expressions/validator.ts (around the epCount !== 1 check near lines
63-72) so that it permits epCount === 0 when the action node has an expressions property
(i.e., allow zero entry_points if expressions are present), preserving the existing
requirement of exactly one entry_point when neither expressions nor rules are present.
Make these two changes so schema-level and engine-level validation rules are consistent
and include a brief unit test or assertion demonstrating an action node with only
expressions passes validation.

Heads up!

Your free trial ends tomorrow.
To keep getting your PRs reviewed by Baz, update your team's subscription

Comment on lines +44 to +55
// Mutual exclusion: expressions vs rules vs entry_points on action nodes
if (type === 'action') {
const hasRules = node.rules !== undefined
const hasEntryPoints = node.entry_points !== undefined
const hasExpressions = node.expressions !== undefined

if (hasExpressions && hasRules) {
errors.push({
path: `/nodes/${nodeId}`,
message: 'Action node cannot have both "expressions" and "rules". Use one or the other',
severity: '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.

Schema now allows expressions-only action nodes but packages/engine/src/runner/walker.ts still assumes an entry_point or rules and throws for expressions-only actions — should we update executeAction/walker to short-circuit by evaluating expressions-only actions and setting results without loading an entry_point?

Finding type: Logical Bugs | Severity: 🔴 High


Want Baz to fix this for you? Activate Fixer

Other fix methods

Fix in Cursor

Prompt for AI Agents:

In packages/schema/src/structural.ts around lines 44 to 72 the validator was changed to
allow action nodes that have an "expressions" block mutually exclusive with "rules" and
"entry_points". However, update packages/engine/src/runner/walker.ts (around the earlier
referenced executeAction/walker logic near lines ~174-177) so that when an action node
has expressions present and does NOT have rules or entry_points the runtime
short-circuits: evaluate the expressions (reuse the existing expression evaluator used
elsewhere), populate the action result/output/state accordingly, and return/advance
without attempting to load or call an entry_point or rules. Also review and, if
necessary, update packages/schema/src/types.generated.ts and
packages/schema/src/serialize.ts to ensure the engine and serializer/types remain
consistent with expression-only action nodes, and add/adjust unit tests to cover
expression-only actions.

Heads up!

Your free trial ends tomorrow.
To keep getting your PRs reviewed by Baz, update your team's subscription

Comment on lines 25 to 31
'label',
'description',
'notes',
'data_class',
'metadata',
'position',
'entry_points',
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

NODE_KEY_PREFIX inserts data_class before metadata and entry_points, breaking CLAUDE.md's canonical order that requires metadata and entry_points directly after description — should we move data_class so metadata/entry_points remain after description or update CLAUDE.md and align serializers with the chosen ordering?

Finding type: AI Coding Guidelines | Severity: 🟠 Medium


Want Baz to fix this for you? Activate Fixer

Other fix methods

Fix in Cursor

Prompt for AI Agents:

In packages/schema/src/serialize.ts around lines 25 to 31, the NODE_KEY_PREFIX was
modified to insert 'data_class' before 'metadata' and 'position', which breaks the
canonical node field order documented in CLAUDE.md (description should be followed
immediately by metadata and entry_points). Fix by moving 'data_class' out of the spot
before 'metadata' so that NODE_KEY_PREFIX is restored to label, description, metadata,
entry_points, ...; place 'data_class' after position or at the end of the prefix
(whichever preserves the CLAUDE.md canonical order). Then review serializeNode (around
lines 154-216) and the new lane/field serializers you added to ensure special-casing for
data_class, expressions, and entry_points still emits keys in the chosen canonical
order; if you decide to adopt a new canonical ordering instead, update CLAUDE.md to
document the exact order and adjust tests/serialization code accordingly.

Heads up!

Your free trial ends tomorrow.
To keep getting your PRs reviewed by Baz, update your team's subscription

Comment on lines +134 to +140
if (key === 'data_class' && Array.isArray(value)) {
const seq = new YAMLSeq()
for (const item of value as string[]) {
seq.add(createScalar(item))
}
laneMap.add(new Pair(key, seq))
} else {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

serializeLanes copies data_class arrays into a YAMLSeq, which is identical to the block added inside serializeNode a few lines later (lines 164‑170). If we ever need to change how data_class values are emitted (e.g. formatting, escaping, or enforcing ordering), we would need to touch both blocks. Can we extract a small helper such as function addArrayField(map: YAMLMap, key: string, values: string[]) and reuse it in both serializeLanes and serializeNode so the serialization behaviour stays consistent and easy to update?

Finding type: Code Dedup and Conventions | Severity: 🟢 Low


Want Baz to fix this for you? Activate Fixer

Heads up!

Your free trial ends tomorrow.
To keep getting your PRs reviewed by Baz, update your team's subscription

@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying flowprint with  Cloudflare Pages  Cloudflare Pages

Latest commit: 298527c
Status: ✅  Deploy successful!
Preview URL: https://92b064c2.flowprint.pages.dev
Branch Preview URL: https://feat-engine-pr0c-schema-addi.flowprint.pages.dev

View logs

@albertgwo
Copy link
Copy Markdown
Contributor Author

Code Review Findings

Critical invariants verified

Important (80-89 confidence)

1. PR description enum values don't match implementation (85)

  • Description says data_class enum is public/internal/confidential/restricted
  • Code has: "enum": ["pii", "financial", "credentials", "internal"]
  • Fix: Update PR description to match actual implementation.

2. data_class array allows duplicates (82)

  • File: packages/schema/flowprint.schema.json (all 8 occurrences)
  • Missing "uniqueItems": true. Document like data_class: ["pii", "pii", "pii"] passes validation.
  • Fix: Add "uniqueItems": true to each data_class array definition.

3. data_class schema duplicated 8 times without $ref (80)

  • File: packages/schema/flowprint.schema.json
  • Identical block copy-pasted into Lane + 7 node types. Every other reusable sub-schema uses $ref to definitions. Future enum changes require 8 edits.
  • Fix: Extract to definitions/DataClassification and use $ref.

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.

1 participant