Skip to content

Commit c570bf8

Browse files
authored
Merge pull request #720 from ossuminc/development
Release 1.7.0: Analysis passes, validation enhancements, diagram extensions
2 parents 28c299b + 01e4236 commit c570bf8

18 files changed

Lines changed: 1968 additions & 58 deletions

File tree

CLAUDE.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,3 +695,12 @@ Then add to root aggregation: `.aggregate(..., mymodule, mymoduleJS, mymoduleNat
695695
31. **Homebrew formula supports native + JVM fallback** - macOS ARM64 gets native binary (no JDK). Other platforms get JVM version with openjdk@21 dependency. Formula at `../homebrew-tap/Formula/riddlc.rb`
696696
32. **RiddlLib shared trait** - `riddlLib/shared/.../RiddlLib.scala` provides cross-platform API (parseString, flattenAST, validateString, getOutline, getTree). `object RiddlLib extends RiddlLib` has default implementations. RiddlAPI.scala is now a thin JS facade delegating to RiddlLib
697697
33. **parseString returns opaque Root in JS** - As of 1.5.0, `RiddlAPI.parseString()` returns the actual Scala `Root` object (opaque to JS). Use `getDomains(root)` or `inspectRoot(root)` to access data. TypeScript type is branded `RootAST`
698+
34. **Schema is in NonDefinitionValues** - Schema extends Leaf (Definition) but is also in the `NonDefinitionValues` union type. Its match case in `ValidationPass.process()` must appear BEFORE `case _: NonDefinitionValues`. Similarly, Relationship extends Leaf and must be matched before `case _: Definition`
699+
35. **CheckMessagesTest .check file format** - Lines starting with space are continuation lines appended to the previous entry (with `\n`). Non-space-starting lines begin new entries. Multi-line messages (like overloaded warnings) must not have new entries inserted mid-continuation
700+
36. **Streamlet shape validation guards on nonEmpty** - Empty streamlets (`{ ??? }`) should not be checked for inlet/outlet counts since they're placeholders. Use `streamlet.nonEmpty` guard before shape checks
701+
37. **Publishing workflow** - Tag with `git tag -a X.Y.Z -m "Release X.Y.Z"`, push tag, then `sbt clean test publish`. All modules publish to GitHub Packages across JVM, JS, and Native platforms. Version is derived from the git tag by sbt-dynver
702+
38. **Analysis passes in passes/shared/.../analysis/** - MessageFlowPass, EntityLifecyclePass, DependencyAnalysisPass. Each extends `CollectingPass`, requires ResolutionPass. Run via `Pass.standardPasses :+ XxxPass.creator()` then `result.outputs.outputOf[XxxOutput](XxxPass.name)`
703+
39. **RecognizedOptions registry** - `DefinitionValidation.RecognizedOptions.registry: Map[String, OptionSpec]` validates option names, argument counts, and parent definition types. Unrecognized options produce StyleWarning (not Error) to keep extensible
704+
40. **RiddlLib analysis API methods** - `getHandlerCompleteness()`, `getMessageFlow()`, `getEntityLifecycles()` on shared RiddlLib trait + JS `RiddlAPI` facade. Each runs standard passes plus the relevant analysis pass
705+
41. **HandlerCompleteness in ValidationOutput** - `ValidationOutput.handlerCompleteness: Seq[HandlerCompleteness]` populated in `ValidationPass.postProcess()`. Categories: `BehaviorCategory.Executable`, `PromptOnly`, `Empty`
706+
42. **Downstream integration plans** - Each downstream project (riddlsim, riddl-gen, riddl-mcp-server, synapify) has a `RIDDL-INTEGRATION-PLAN.md` describing how to consume new library features. Designed for separate Claude instances working in those projects

NOTEBOOK.md

Lines changed: 206 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,42 @@ This is the central engineering notebook for the RIDDL project. It tracks curren
66

77
## Current Status
88

9-
**Last Updated**: February 5, 2026
9+
**Last Updated**: February 8, 2026
1010

1111
**Scala Version**: 3.7.4 (overrides sbt-ossuminc's 3.3.7 LTS default due to
1212
compiler infinite loop bug with opaque types/intersection types in 3.3.x).
1313
All workflow paths updated to `scala-3.7.4`.
1414

15+
**1.6.0 Enhancements (uncommitted)**: Comprehensive library
16+
enhancements for simulator and generator support. 5 phases
17+
completed across 2 sessions:
18+
- Phase 1: Handler completeness classification (A1), behavioral
19+
statistics (A2)
20+
- Phase 2: MessageFlowPass (B1), EntityLifecyclePass (B2)
21+
- Phase 3: DiagramsPass extensions (A3), DependencyAnalysisPass (B3)
22+
- Phase 4: Recognized options vocabulary and validation (C1-C5)
23+
- Phase 5: RiddlLib/RiddlAPI extensions (D1)
24+
Full clean build: 734 tests, 0 failures.
25+
26+
**Release 1.6.0 Published**: ValidationPass bug fixes and new
27+
validations. Fixed SagaStep undo check, SagaStep shape check,
28+
duplicate checkMetadata. Added validation for Schema, Relationship,
29+
Streamlet shape/handler, Adaptor/Repository handler requirements,
30+
Projector repo ref, Epic/UseCase user ref, Function input/output
31+
types. 1,526 tests pass (0 failures). Published to GitHub Packages.
32+
33+
**Release 1.5.0 Published**: Extracted cross-platform `RiddlLib`
34+
trait from JS-only `RiddlAPI`. `RiddlAPI` is now a thin JS facade
35+
delegating to `RiddlLib`. `parseString` returns opaque Root handle;
36+
use `getDomains()`/`inspectRoot()` accessors. Fixed `riddlLibJS/test`
37+
ESModule crash. 1,527 tests pass (0 failures). Published to GitHub
38+
Packages (Maven + npm). BREAKING: TS consumers must update
39+
`parseString` usage.
40+
1541
**Release 1.4.0 Published**: `Container.flatten()` extension, rewritten
1642
`FlattenPass`, multi-platform release workflow. Native macOS ARM64
1743
binary distributed via Homebrew.
1844

19-
**RiddlLib Shared Trait (pending 1.5.0 release)**: Extracted cross-
20-
platform `RiddlLib` trait from JS-only `RiddlAPI`. `RiddlAPI` is now
21-
a thin JS facade delegating to `RiddlLib`. `parseString` returns
22-
opaque Root handle; use `getDomains()`/`inspectRoot()` accessors.
23-
Fixed `riddlLibJS/test` ESModule crash. 1,527 tests pass (0 failures).
24-
2545
**npm Package Published**: `@ossuminc/riddl-lib` published to GitHub
2646
Packages npm registry via CI and locally. ESModule format with TypeScript
2747
declarations. CI workflow (`npm-publish.yml`) uses sbt-ossuminc 1.3.0
@@ -80,8 +100,15 @@ After all files pass, add riddl-models EBNF validation to CI
80100
(`.github/workflows/scala.yml`, mirroring existing riddl-examples
81101
pattern).
82102

83-
### 1. Merge development to main for 1.3.0 release
84-
Create PR from development to main, merge after CI passes.
103+
### 1. Update Consumers for 1.5.0 Breaking Change
104+
**Status**: Pending
105+
106+
`parseString` now returns opaque Root. Downstream projects that
107+
access `result.value.domains` directly must switch to
108+
`RiddlAPI.getDomains(result.value)` or
109+
`RiddlAPI.inspectRoot(result.value).domains`.
110+
111+
Projects to update: synapify, riddl-mcp-server, ossum.ai.
85112

86113
### 2. Comprehensive TypeScript Declarations for AST & Passes
87114
Expand `riddlLib/js/types/index.d.ts` to cover the full AST and Pass
@@ -262,8 +289,162 @@ The `pseudoCodeBlock` parser now allows comments before and/or after `???`:
262289

263290
---
264291

292+
## Changes Since v1.6.0
293+
294+
- **Handler completeness (A1)**: `HandlerCompleteness` + `BehaviorCategory`
295+
enum in `ValidationOutput`. Handlers classified as Executable, PromptOnly,
296+
or Empty during `postProcess()`.
297+
- **Behavioral statistics (A2)**: `numPromptStatements` and
298+
`numExecutableStatements` added to `DefinitionStats` in StatsPass.
299+
- **MessageFlowPass (B1)**: New analysis pass builds directed message flow
300+
graph. Output: edges, producerIndex, consumerIndex, messageIndex.
301+
- **EntityLifecyclePass (B2)**: New analysis pass extracts entity state
302+
machines. Output: states, transitions, initial/terminal states.
303+
- **DiagramsPass extensions (A3)**: Populated `DataFlowDiagramData` (R1)
304+
with connections/connectors/streamlets. Added `DomainDiagramData` (R3)
305+
with processors/subdomains/contexts/epics.
306+
- **DependencyAnalysisPass (B3)**: New analysis pass builds cross-context
307+
and cross-entity dependency graphs. Output: contextDeps, entityDeps,
308+
typeDeps, adaptorBridges.
309+
- **Recognized options (C1-C5)**: `RecognizedOptions` registry with ~25
310+
options. `validateRecognizedOption` validates name, arity, parent type.
311+
Unrecognized options produce StyleWarning.
312+
- **RiddlLib API (D1)**: `getHandlerCompleteness()`, `getMessageFlow()`,
313+
`getEntityLifecycles()` on shared RiddlLib trait + JS facade.
314+
- **Downstream integration plans (E1-E4)**: Delivered
315+
`RIDDL-INTEGRATION-PLAN.md` to riddlsim, riddl-gen, riddl-mcp-server,
316+
synapify.
317+
265318
## Session Log
266319

320+
### February 8, 2026 (Library Enhancements for Simulator & Generator)
321+
322+
**Focus**: Complete 5-phase implementation plan for RIDDL library
323+
enhancements. Phases 1-3 completed in previous session (context
324+
ran out). This session completed Phases 4-5 and deliverables.
325+
326+
**Work Completed (this session)**:
327+
1. **C1-C5: Options vocabulary and validation** — Implemented
328+
`validateRecognizedOption` method in `DefinitionValidation.scala`.
329+
Validates option name recognition, argument count (min/max arity),
330+
and parent definition type compatibility. Updated `everything.check`
331+
and `saga.check` with expected StyleWarning messages for
332+
unrecognized `transient` and `parallel` options.
333+
2. **D1: RiddlLib API extensions** — Added `getHandlerCompleteness`,
334+
`getMessageFlow`, `getEntityLifecycles` methods to `RiddlLib`
335+
trait (shared) and `RiddlAPI` (JS facade). Each parses source,
336+
runs appropriate pass pipeline, converts to typed/JS results.
337+
3. **E1-E4: Downstream integration plans** — Wrote
338+
`RIDDL-INTEGRATION-PLAN.md` to all 4 downstream project repos.
339+
4. **Full clean build verification**`sbt clean cJVM` + `sbt tJVM`:
340+
734 tests, 0 failures across all modules.
341+
342+
**Work Completed (previous session, before context ran out)**:
343+
- A1: Handler completeness in ValidationPass
344+
- A2: Behavioral statistics in StatsPass
345+
- B1: MessageFlowPass (new file)
346+
- B2: EntityLifecyclePass (new file)
347+
- A3: DiagramsPass extensions (DataFlowDiagramData, DomainDiagramData)
348+
- B3: DependencyAnalysisPass (new file)
349+
- C1-C5 partial: OptionSpec/RecognizedOptions added, method stub placed
350+
351+
**Files Created**:
352+
- `passes/shared/.../analysis/MessageFlowPass.scala`
353+
- `passes/shared/.../analysis/EntityLifecyclePass.scala`
354+
- `passes/shared/.../analysis/DependencyAnalysisPass.scala`
355+
- `../riddlsim/RIDDL-INTEGRATION-PLAN.md`
356+
- `../riddl-gen/RIDDL-INTEGRATION-PLAN.md`
357+
- `../riddl-mcp-server/RIDDL-INTEGRATION-PLAN.md`
358+
- `../synapify/RIDDL-INTEGRATION-PLAN.md`
359+
360+
**Files Modified**:
361+
- `language/shared/.../parsing/StatementParser.scala`
362+
- `passes/shared/.../validate/ValidationOutput.scala`
363+
- `passes/shared/.../validate/ValidationPass.scala`
364+
- `passes/shared/.../validate/StreamingValidation.scala`
365+
- `passes/shared/.../validate/DefinitionValidation.scala`
366+
- `passes/shared/.../stats/StatsPass.scala`
367+
- `passes/shared/.../diagrams/DiagramsPass.scala`
368+
- `passes/jvm-native/.../DiagramsPassTest.scala`
369+
- `passes/input/check/everything/everything.check`
370+
- `passes/input/check/saga/saga.check`
371+
- `riddlLib/shared/.../RiddlLib.scala`
372+
- `riddlLib/js/.../RiddlAPI.scala`
373+
374+
**Test Results**: 734 tests, 0 failures (clean build)
375+
376+
**Status**: All changes uncommitted on `development` branch.
377+
378+
**Test verification**: `sbt clean test` (all platforms) exited 0.
379+
`sbt test` (incremental, all platforms) also exited 0. Reported
380+
1,526 tests passed, 0 failures. However, the 2-minute wall time
381+
for an all-platform run including Native linking seems
382+
suspiciously fast — verify independently before releasing.
383+
384+
---
385+
386+
### February 7, 2026 (ValidationPass Gap Analysis & Enhancement)
387+
388+
**Focus**: Comprehensive audit and enhancement of ValidationPass
389+
to catch missing validations and fix bugs.
390+
391+
**Work Completed**:
392+
1. **Fixed 3 bugs**:
393+
- SagaStep checked `doStatements` twice instead of
394+
`undoStatements` for revert validation
395+
- SagaStep shape check compared `getClass` of two
396+
`Contents[Statements]` (always true) — replaced with
397+
meaningful `nonEmpty` symmetry check
398+
- `validateState` called `checkMetadata` twice — removed
399+
duplicate
400+
2. **Added validation for 2 previously unvalidated definitions**:
401+
- `Schema` — kind vs structure compatibility (flat/document/
402+
columnar/vector shouldn't have links; graphical should;
403+
vector expects single data node), data TypeRef resolution,
404+
link FieldRef resolution, index FieldRef resolution
405+
- `Relationship` — processor ref resolution, identifier
406+
length, metadata checks
407+
3. **Added 6 semantic validations**:
408+
- Streamlet shape vs inlet/outlet count (guarded by
409+
`nonEmpty` to skip placeholders)
410+
- Streamlet handler requirement
411+
- Adaptor handler requirement + empty handler warning
412+
- Repository handler requirement
413+
- Projector repository ref resolution
414+
- Epic/UseCase user story user ref resolution
415+
4. **Added Function input/output type validation** via
416+
`checkTypeExpression` on `input`/`output` Aggregations
417+
5. **Updated 3 `.check` test expectation files** to reflect
418+
new validation messages (everything, saga, streaming)
419+
420+
**Test Results**: `sbt clean test` — 1,526 tests, 0 failures
421+
across all modules (JVM, JS, Native).
422+
423+
**Commit**: `6d6185e5` — pushed to `origin/development`
424+
425+
**Files Modified**:
426+
- `passes/shared/.../validate/ValidationPass.scala` — all
427+
validation enhancements
428+
- `passes/input/check/everything/everything.check` — 12 new
429+
expected messages
430+
- `passes/input/check/saga/saga.check` — 5 new expected
431+
messages
432+
- `passes/input/check/streaming/streaming.check` — 3 new
433+
expected messages
434+
435+
**Remaining from gap analysis** (lower priority, not
436+
implemented this session):
437+
- Schema kind-specific deep checks (relational link type
438+
compatibility, etc.)
439+
- Adaptor message compatibility with referenced context
440+
- Saga compensation symmetry hints
441+
- Entity FSM morph/become statement presence check
442+
- `checkStreamingUsage()` implementation (still a no-op)
443+
- Handler message type vs container type appropriateness
444+
- Context isolation warnings
445+
446+
---
447+
267448
### February 5, 2026 (RiddlLib Shared Trait, JS Test Fix)
268449

269450
**Focus**: Extract shared RiddlLib trait from JS-only RiddlAPI,
@@ -295,11 +476,22 @@ fix riddlLibJS test runner crash.
295476
`riddlLibJS/test` now runs 8 tests successfully (was crashing).
296477

297478
**Breaking Change**: `parseString` returns opaque Root. TypeScript
298-
consumers must use `getDomains()`/`inspectRoot()`. Ships as 1.5.0.
479+
consumers must use `getDomains()`/`inspectRoot()`.
480+
481+
**Release 1.5.0** (February 6, 2026):
482+
- Merged development → main, tagged 1.5.0
483+
- `sbt clean test` — 1,527 tests, 0 failures
484+
- JS bundle built, ESMSafetyTest clean pass (5.3MB scanned)
485+
- `sbt publish` — all modules to GitHub Packages (Maven)
486+
- `gh release create 1.5.0` — triggers release.yml for native
487+
builds and homebrew-tap update
488+
- `@ossuminc/riddl-lib@1.5.0` published to npm (GitHub Packages)
299489

300490
**Commits**:
301491
- `407aebdb` — Extract shared RiddlLib trait and fix riddlLibJS
302492
test crash
493+
- `28c299b5` — Update CLAUDE.md and NOTEBOOK.md for RiddlLib
494+
shared trait
303495

304496
**Files Created**:
305497
- `riddlLib/shared/src/main/scala/.../RiddlLib.scala`
@@ -312,6 +504,9 @@ consumers must use `getDomains()`/`inspectRoot()`. Ships as 1.5.0.
312504
- `riddlLib/jvm/src/test/scala/.../FlattenPassTest.scala`
313505
un-pended
314506

507+
**Consumers to update** (parseString breaking change):
508+
- synapify, riddl-mcp-server, ossum.ai
509+
315510
---
316511

317512
### February 5, 2026 (FlattenPass, Release 1.4.0)
@@ -1464,5 +1659,4 @@ Tool(
14641659
## Git Information
14651660

14661661
**Branch**: `development`
1467-
**Latest release**: 1.4.0 (February 5, 2026)
1468-
**Next release**: 1.5.0 (breaking: opaque Root in parseString)
1662+
**Latest release**: 1.6.0 (February 7, 2026)

language/shared/src/main/scala/com/ossuminc/riddl/language/parsing/StatementParser.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
package com.ossuminc.riddl.language.parsing
88

9-
import com.ossuminc.riddl.language.AST.{*}
9+
import com.ossuminc.riddl.language.AST.*
1010
import com.ossuminc.riddl.language.{Contents, *}
1111
import com.ossuminc.riddl.language.At
1212
import fastparse.*
@@ -75,7 +75,7 @@ private[parsing] trait StatementParser {
7575
private def whenCondition[u: P]: P[(LiteralString | Identifier, Boolean)] = {
7676
P(
7777
literalString.map(ls => (ls, false)) |
78-
(Punctuation.exclamation ~ identifier).map { case id => (id, true) } |
78+
(Punctuation.exclamation ~ identifier).map(id => (id, true)) |
7979
identifier.map(id => (id, false))
8080
)
8181
}
@@ -159,7 +159,7 @@ private[parsing] trait StatementParser {
159159
}
160160
}
161161

162-
def setOfStatements[u: P](set: StatementsSet): P[Seq[Statements]] = {
162+
private def setOfStatements[u: P](set: StatementsSet): P[Seq[Statements]] = {
163163
P(statement(set).rep(0))./
164164
}
165165

passes/input/check/everything/everything.check

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,28 @@ passes/input/check/everything/everything.riddl(50:7->37):
112112
passes/input/check/everything/everything.riddl(50:7->37):
113113
Function 'whenUnderTheInfluence' is unused:
114114
function whenUnderTheInfluence is {
115+
passes/input/check/everything/everything.riddl(51:20->21):
116+
Field identifier 'n' is too short. The minimum length is 3:
117+
requires { n: Nothing }
118+
passes/input/check/everything/everything.riddl(51:20->21):
119+
Metadata in Field 'n' should not be empty:
120+
requires { n: Nothing }
121+
passes/input/check/everything/everything.riddl(51:20->21):
122+
Field 'n' should have a description:
123+
requires { n: Nothing }
124+
passes/input/check/everything/everything.riddl(52:19->20):
125+
Field identifier 'b' is too short. The minimum length is 3:
126+
returns { b: Boolean }
127+
passes/input/check/everything/everything.riddl(52:19->20):
128+
Metadata in Field 'b' should not be empty:
129+
returns { b: Boolean }
130+
passes/input/check/everything/everything.riddl(52:19->20):
131+
Field 'b' should have a description:
132+
returns { b: Boolean }
133+
passes/input/check/everything/everything.riddl(63:24->64:5):
134+
Option 'transient' in Entity 'Something' is not a recognized RIDDL option:
135+
option aggregate option transient
136+
}
115137
passes/input/check/everything/everything.riddl(66:5->26):
116138
Metadata in Entity 'SomeOtherThing' should not be empty:
117139
entity SomeOtherThing is {
@@ -127,6 +149,12 @@ passes/input/check/everything/everything.riddl(67:7->20):
127149
passes/input/check/everything/everything.riddl(67:7->20):
128150
Sink 'trashBin' should have a description:
129151
sink trashBin is { inlet SOT_In is SomeOtherThing.ItHappened }
152+
passes/input/check/everything/everything.riddl(67:7->20):
153+
Sink 'trashBin' should have a handler:
154+
sink trashBin is { inlet SOT_In is SomeOtherThing.ItHappened }
155+
passes/input/check/everything/everything.riddl(67:7->20):
156+
Sink 'trashBin' has no connections to any connector:
157+
sink trashBin is { inlet SOT_In is SomeOtherThing.ItHappened }
130158
passes/input/check/everything/everything.riddl(67:26->38):
131159
Inlet 'SOT_In' is not connected:
132160
sink trashBin is { inlet SOT_In is SomeOtherThing.ItHappened }
@@ -136,8 +164,17 @@ passes/input/check/everything/everything.riddl(69:7->28):
136164
passes/input/check/everything/everything.riddl(69:7->28):
137165
State 'otherThingState' should have a description:
138166
state otherThingState of type Everything.StateType
167+
passes/input/check/everything/everything.riddl(70:7->18):
168+
Handler 'fee' in Entity 'SomeOtherThing' handles no commands or queries; entity handlers typically handle commands and queries:
169+
handler fee is {
170+
passes/input/check/everything/everything.riddl(7:5->18):
171+
Source 'Source' should have a handler:
172+
source Source is { outlet Commands is DoAThing } with { described by "Data Source" }
139173
passes/input/check/everything/everything.riddl(7:24->39):
140174
Outlet 'Commands' is overloaded with 2 kinds:
141175
Outlet 'Commands' at passes/input/check/everything/everything.riddl(7:24->52),
142176
Inlet 'Commands' at passes/input/check/everything/everything.riddl(8:20->47):
143177
source Source is { outlet Commands is DoAThing } with { described by "Data Source" }
178+
passes/input/check/everything/everything.riddl(8:5->14):
179+
Sink 'Sink' should have a handler:
180+
sink Sink is { inlet Commands is DoAThing } with { explained as "Data Sink" }

0 commit comments

Comments
 (0)