@mamund/tram 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,749 @@
1
+ # Executable Behavioral Modeling for APIs
2
+
3
+ *A layered approach to modeling observable API behavior*
4
+
5
+ Most API test suites accumulate over time. A smoke test is added to
6
+ verify deployment. A schema check appears later. Workflow scenarios
7
+ arrive after production failures. Authorization checks are folded in
8
+ after a security review. Eventually the entire collection becomes
9
+ difficult to reason about because unrelated concerns sit side-by-side
10
+ with little distinction between them.
11
+
12
+ A route existence check and a workflow continuity check may both be
13
+ called "tests," but they answer very different questions.
14
+
15
+ TRAM began as an exploratory attempt to simplify executable API
16
+ assertions. Along the way, another pattern started to emerge. API
17
+ assertions appeared to fall naturally into layers of observable
18
+ behavior. Some assertions focused on whether an endpoint existed at all.
19
+ Others focused on resource shape, action semantics, workflow continuity,
20
+ or governance constraints.
21
+
22
+ This document outlines one possible way to think about those layers.
23
+
24
+ The goal here is not to define a formal testing taxonomy. The layers
25
+ described below overlap in places and will likely evolve over time. The
26
+ intent is simpler than that: separate concerns clearly enough that
27
+ manifests become easier to generate, review, reason about, and maintain.
28
+
29
+ ## A progressive model
30
+
31
+ The layers described in this document can be viewed as a progression
32
+ from basic API capability verification toward operational and policy
33
+ modeling.
34
+
35
+ | Level | Name | Primary Question | Focus |
36
+ |------:|------|------------------|-------|
37
+ | 0 | Surface | Can the API be reached? | Availability |
38
+ | 1 | Shape | Do resources and affordances appear correctly? | Representation |
39
+ | 2 | Safe behavior | Do navigation and query interactions behave correctly? | Observation |
40
+ | 3 | Unsafe behavior | Do isolated state-changing actions behave correctly? | Mutation |
41
+ | 4 | Workflow | Can meaningful operational narratives be completed successfully? | Continuity |
42
+ | 5 | Governance | Are policies, constraints, permissions, and semantic rules enforced correctly? | Policy |
43
+
44
+ Levels 0--3 primarily verify observable API capability. Workflow and
45
+ governance layers move closer to operational narratives, policy
46
+ modeling, domain constraints, and business intent.
47
+
48
+ Another useful way to view the progression is as a gradual expansion of
49
+ concern. Surface and shape focus on what the API exposes. Safe and
50
+ unsafe behavior focus on how the API behaves. Workflow and governance
51
+ focus on whether the API supports meaningful operational goals while
52
+ respecting domain rules and organizational constraints.
53
+
54
+ Viewed this way, each layer builds upon the layers beneath it. Higher
55
+ layers do not replace lower layers; they depend on them. A workflow
56
+ assertion assumes that routes exist, representations are recognizable,
57
+ and state-changing actions function correctly. Governance assertions
58
+ often span all preceding layers, expressing the rules that determine
59
+ which behaviors are legitimate within a particular domain.
60
+
61
+ ## Two dimensions of TRAM assertions
62
+
63
+ One of the most useful distinctions to emerge from this work is that
64
+ behavioral intent and assertion location are not the same thing.
65
+
66
+ Behavioral layers describe what kind of question an assertion is asking.
67
+ Assertion targets describe where observations occur during the HTTP
68
+ interaction.
69
+
70
+ For example, a governance assertion may inspect:
71
+
72
+ - a protocol status code
73
+ - a metadata header
74
+ - a body representation
75
+
76
+ while still remaining fundamentally a governance concern.
77
+
78
+ Similarly, a shape assertion may verify:
79
+
80
+ - JSON structure in the response body
81
+ - media type metadata
82
+ - pagination headers
83
+
84
+ without becoming a workflow assertion.
85
+
86
+ In practice, TRAM assertions tend to inspect three observable locations.
87
+
88
+ ### Protocol
89
+
90
+ Protocol assertions focus on HTTP-level mechanics:
91
+
92
+ - methods
93
+ - status codes
94
+ - redirects
95
+ - content negotiation
96
+ - caching behavior
97
+
98
+ Examples:
99
+
100
+ ``` json
101
+ {
102
+ "method": "GET",
103
+ "path": "/tasks",
104
+ "expect": {
105
+ "status": 200,
106
+ "headers": [
107
+ {
108
+ "name": "content-type",
109
+ "contains": "application/json"
110
+ },
111
+ {
112
+ "name": "api-key",
113
+ "exists": true
114
+ }
115
+ ]
116
+ }
117
+ }
118
+ ```
119
+
120
+ ### Metadata
121
+
122
+ Metadata assertions focus on information carried outside the primary
123
+ representation:
124
+
125
+ - headers
126
+ - links
127
+ - pagination controls
128
+ - authentication challenges
129
+ - ETags
130
+ - continuation tokens
131
+ - rate-limit information
132
+
133
+ In hypermedia-oriented systems, metadata often carries important runtime
134
+ behavior. Affordances may appear in headers, link maps, or negotiated
135
+ representations rather than inside resource bodies alone.
136
+
137
+ ### Body
138
+
139
+ Body assertions focus on the representation itself:
140
+
141
+ - resource properties
142
+ - collections
143
+ - embedded affordances
144
+ - payload content
145
+ - returned state
146
+
147
+ These assertion targets exist independently from the behavioral layers
148
+ described below.
149
+
150
+ ## Level 0: Surface --- what is exposed?
151
+
152
+ The simplest TRAM assertion asks a minimal question:
153
+
154
+ > Does the published endpoint respond?
155
+
156
+ A surface manifest verifies the observable API surface:
157
+
158
+ - published routes
159
+ - supported methods
160
+ - callable interfaces
161
+
162
+ For example:
163
+
164
+ ``` json
165
+ {
166
+ "name": "List tasks endpoint responds",
167
+ "method": "GET",
168
+ "path": "/tasks",
169
+ "expect": {
170
+ "status": 200
171
+ }
172
+ }
173
+ ```
174
+
175
+ Surface assertions are intentionally lightweight. They do not verify
176
+ business correctness, workflow continuity, or resource semantics. They
177
+ simply confirm that the advertised interface exists and responds as
178
+ expected.
179
+
180
+ This level is useful for:
181
+
182
+ - smoke testing
183
+ - deployment validation
184
+ - route inventory verification
185
+ - documentation cross-checking
186
+
187
+ Surface assertions also help separate observed capability from assumed
188
+ capability. A system may support editing resources while intentionally
189
+ omitting deletion. A surface manifest makes that distinction visible
190
+ immediately.
191
+
192
+ ## Level 1: Shape --- what is represented?
193
+
194
+ Shape assertions move from endpoint existence to representation
195
+ structure.
196
+
197
+ At this layer, the question becomes:
198
+
199
+ > Does this resemble the advertised resource?
200
+
201
+ Shape assertions typically verify:
202
+
203
+ - expected properties
204
+ - collection structures
205
+ - embedded affordances
206
+ - representation composition
207
+ - basic typing expectations
208
+
209
+ Examples:
210
+
211
+ ``` json
212
+ {
213
+ "path": "$.id",
214
+ "type": "string"
215
+ }
216
+
217
+ {
218
+ "path": "$.priority",
219
+ "type": "number"
220
+ }
221
+
222
+ {
223
+ "path": "$._links",
224
+ "type": "object"
225
+ }
226
+ ```
227
+
228
+ Shape manifests often verify affordance presence explicitly:
229
+
230
+ ``` json
231
+ {
232
+ "path": "$._links",
233
+ "hasProperties": [
234
+ "self",
235
+ "edit",
236
+ "updateStatus",
237
+ "assignUser"
238
+ ]
239
+ }
240
+ ```
241
+
242
+ This layer maps closely to the RESOURCE concepts used in API Stories.
243
+ The focus is on representation shape rather than behavioral correctness.
244
+
245
+ That distinction matters.
246
+
247
+ A representation may be structurally valid while still violating domain
248
+ rules. For example:
249
+
250
+ ``` json
251
+ {
252
+ "status": "flying-purple-banana"
253
+ }
254
+ ```
255
+
256
+ may satisfy basic shape assertions while remaining semantically invalid
257
+ within the domain.
258
+
259
+ Shape assertions focus on structural validity and recognizable
260
+ representation patterns. Governance assertions, discussed later, address
261
+ semantic legitimacy and policy constraints.
262
+
263
+ Recent additions to the TRAM assertion model also support optional
264
+ property assertions. This allows manifests to model conditional
265
+ representation structure without collapsing into rigid schema
266
+ enforcement.
267
+
268
+ For example:
269
+
270
+ ``` json
271
+ {
272
+ "path": "$",
273
+ "each": {
274
+ "property": "description",
275
+ "optional": true,
276
+ "type": "string"
277
+ }
278
+ }
279
+ ```
280
+
281
+ This assertion means the `description` property may be absent while
282
+ still requiring valid structure whenever the property appears.
283
+
284
+ This distinction becomes important in evolving systems, sparse
285
+ representations, and hypermedia-oriented APIs where representation shape
286
+ may vary legitimately at runtime.
287
+
288
+ This distinction is especially important for type assertions.
289
+
290
+ ``` json
291
+ {
292
+ "path": "$.priority",
293
+ "type": "number"
294
+ }
295
+ ```
296
+
297
+ is primarily a shape concern because it verifies structural form.
298
+
299
+ Meanwhile:
300
+
301
+ ``` json
302
+ {
303
+ "path": "$.priority",
304
+ "range": {
305
+ "min": 1,
306
+ "max": 5
307
+ }
308
+ }
309
+ ```
310
+
311
+ is fundamentally a governance concern because it expresses domain
312
+ legitimacy rather than representation structure.
313
+
314
+ ## Level 2: Safe behavior --- what can be observed?
315
+
316
+ Safe behavior assertions verify interactions that do not intentionally
317
+ change server state.
318
+
319
+ Examples include:
320
+
321
+ - navigation
322
+ - filtering
323
+ - search
324
+ - affordance traversal
325
+ - query operations
326
+
327
+ Examples:
328
+
329
+ ``` json
330
+ {
331
+ "name": "Filter completed tasks",
332
+ "method": "GET",
333
+ "path": "/tasks",
334
+ "query": {
335
+ "status": "completed"
336
+ },
337
+ "expect": {
338
+ "status": 200
339
+ }
340
+ }
341
+ ```
342
+
343
+ or:
344
+
345
+ ``` json
346
+ {
347
+ "path": "$._links.goTaskList.href",
348
+ "equals": "/tasks"
349
+ }
350
+ ```
351
+
352
+ Safe behavior manifests verify semantic interaction rather than HTTP
353
+ mechanics alone.
354
+
355
+ This distinction becomes especially useful in hypermedia-oriented
356
+ systems where meaningful actions may be expressed through:
357
+
358
+ - links
359
+ - forms
360
+ - metadata
361
+ - affordances
362
+ - negotiated runtime state
363
+
364
+ rather than through static route catalogs alone.
365
+
366
+ In hypermedia-oriented systems, runtime discoverability itself becomes
367
+ part of observable behavior. Testing therefore expands beyond endpoint
368
+ correctness into questions of navigability, affordance exposure, and
369
+ runtime coordination surfaces.
370
+
371
+ Recent additions to the assertion model also support object-map
372
+ traversal (`eachProperty`), allowing manifests to validate
373
+ affordance-oriented structures such as hypermedia link maps without
374
+ introducing scripting or custom matcher code.
375
+
376
+ For example:
377
+
378
+ ``` json
379
+ {
380
+ "path": "$._links",
381
+ "eachProperty": {
382
+ "hasProperties": ["href", "method"]
383
+ }
384
+ }
385
+ ```
386
+
387
+ TRAM distinguishes between:
388
+
389
+ - `each` for arrays
390
+ - `eachProperty` for object maps
391
+
392
+ It also distinguishes between:
393
+
394
+ - `path` for structural traversal
395
+ - `property` for scalar leaf assertions
396
+
397
+ This allows nested affordance validation while preserving declarative
398
+ readability.
399
+
400
+ ## Level 3: Unsafe behavior --- what can be changed?
401
+
402
+ Unsafe behavior assertions focus on isolated state-changing operations:
403
+
404
+ - create
405
+ - update
406
+ - assignment
407
+ - status transitions
408
+ - workflow advancement
409
+
410
+ Examples:
411
+
412
+ ``` json
413
+ {
414
+ "name": "Update task status",
415
+ "method": "PUT",
416
+ "path": "/tasks/123/status",
417
+ "bodyType": "json",
418
+ "body": {
419
+ "status": "completed"
420
+ },
421
+ "expect": {
422
+ "status": 200,
423
+ "body": [
424
+ {
425
+ "path": "$.status",
426
+ "equals": "completed"
427
+ }
428
+ ]
429
+ }
430
+ }
431
+ ```
432
+
433
+ At this layer, assertions typically verify:
434
+
435
+ - the action succeeds
436
+ - the expected state change appears
437
+ - the returned representation reflects the mutation
438
+
439
+ Unsafe behavior manifests intentionally avoid accumulated continuity
440
+ assumptions. They focus on isolated semantic actions rather than
441
+ long-running narratives.
442
+
443
+ This layer maps closely to the ACTION elements used in API Stories.
444
+
445
+ TRAM also distinguishes between:
446
+
447
+ - object injection using `$data.*`
448
+ - string interpolation using `${data.*}`
449
+
450
+ This allows manifests to coordinate reusable workflow state while
451
+ preserving readable request construction.
452
+
453
+ ## Level 4: Workflow --- what holds together over time?
454
+
455
+ Workflow assertions verify continuity across multiple interactions.
456
+
457
+ Many systems pass isolated behavior assertions while still failing real
458
+ workflows. State may drift. Side effects may accumulate incorrectly. One
459
+ valid action may unintentionally invalidate another.
460
+
461
+ Workflow manifests focus on coordinated sequences such as:
462
+
463
+ ``` text
464
+ create → edit → complete
465
+ ```
466
+
467
+ or:
468
+
469
+ ``` text
470
+ search → select → update
471
+ ```
472
+
473
+ At this layer, the system is evaluated across:
474
+
475
+ - sequencing
476
+ - accumulated state
477
+ - continuity
478
+ - state preservation
479
+ - cross-action assumptions
480
+
481
+ Workflow assertions are especially valuable in distributed systems where
482
+ correctness often depends on interaction over time rather than isolated
483
+ request handling.
484
+
485
+ This layer also begins to intersect strongly with:
486
+
487
+ - user stories
488
+ - operational scenarios
489
+ - BDD narratives
490
+ - API Story scenarios
491
+
492
+ Earlier layers primarily ask:
493
+
494
+ > Does the API function correctly?
495
+
496
+ Workflow manifests ask:
497
+
498
+ > Can users accomplish meaningful goals successfully?
499
+
500
+ That shift is important. Workflow manifests are often organized around
501
+ operational narratives rather than around individual endpoints.
502
+
503
+ Examples:
504
+
505
+ - task lifecycle workflow
506
+ - assignment workflow
507
+ - completion workflow
508
+ - review workflow
509
+
510
+ rather than:
511
+
512
+ - PUT status tests
513
+ - POST edit tests
514
+
515
+ Recent workflow-oriented manifest patterns also verify accumulated final
516
+ state rather than isolated mutation success alone.
517
+
518
+ For example:
519
+
520
+ ``` text
521
+ create
522
+ read after create
523
+ edit
524
+ update status
525
+ assign user
526
+ set due date
527
+ read final accumulated state
528
+ ```
529
+
530
+ This allows operational continuity itself to become directly
531
+ inspectable.
532
+
533
+ Workflow manifests are also effectively unbounded. As systems evolve,
534
+ new operational narratives emerge naturally.
535
+
536
+ ## Level 5: Governance --- what is permitted?
537
+
538
+ Governance assertions verify constraints, permissions, invariants, and
539
+ policy rules.
540
+
541
+ Historically, these concerns are often grouped under "negative testing"
542
+ or "sad path testing." That framing is useful in some contexts but too
543
+ limited here. Governance assertions are broader than failure conditions
544
+ alone.
545
+
546
+ Governance assertions may verify:
547
+
548
+ - required fields
549
+ - ownership rules
550
+ - authorization
551
+ - legal state transitions
552
+ - read-only restrictions
553
+ - policy invariants
554
+ - rate limits
555
+
556
+ Examples:
557
+
558
+ ``` json
559
+ {
560
+ "expect": {
561
+ "status": 400,
562
+ "body": [
563
+ {
564
+ "path": "$.error",
565
+ "equals": "Missing required field: status"
566
+ }
567
+ ]
568
+ }
569
+ }
570
+ ```
571
+
572
+ The distinction between shape and governance becomes important at this
573
+ layer.
574
+
575
+ Shape asks:
576
+
577
+ > What form does this representation take?
578
+
579
+ Governance asks:
580
+
581
+ > What meanings and constraints apply to it?
582
+
583
+ Governance manifests may describe:
584
+
585
+ - currently enforced rules
586
+ - proposed future rules
587
+ - expected policy boundaries
588
+
589
+ For exploratory systems, this distinction can be useful:
590
+
591
+ ``` text
592
+ Observed governance
593
+ Rules enforced by the running API.
594
+
595
+ Proposed governance
596
+ Rules suggested by the domain model, API Story, or operational requirements.
597
+ ```
598
+
599
+ Governance assertions help make implicit policies observable and
600
+ executable.
601
+
602
+ In some systems, governance rules may also influence representation
603
+ visibility itself. Permissions, workflow state, or policy boundaries may
604
+ legitimately suppress portions of a representation while still
605
+ preserving behavioral correctness.
606
+
607
+ ## Why separate the layers?
608
+
609
+ Separating behavioral concerns into layers offers several practical
610
+ advantages.
611
+
612
+ First, manifests become easier to reason about. A failed surface
613
+ assertion tells a very different story from a failed workflow assertion.
614
+ Separating those concerns improves failure visibility and reduces
615
+ debugging noise.
616
+
617
+ Second, layered manifests are easier to review collaboratively. A
618
+ resource designer may focus primarily on shape assertions while a
619
+ security reviewer focuses on governance assertions.
620
+
621
+ Third, the separation reduces scenario explosion. Traditional behavioral
622
+ suites often accumulate large, overlapping workflows that combine
623
+ representation concerns, policy checks, state transitions, and
624
+ authorization rules into single scenarios. Smaller layered assertions
625
+ are easier to compose and evolve over time.
626
+
627
+ The layered structure also narrows debugging scope operationally.
628
+
629
+ If a workflow assertion fails while earlier surface, shape, and isolated
630
+ mutation layers continue passing, the failure can often be localized to
631
+ continuity, accumulation, or sequencing behavior rather than
632
+ representation or transport concerns.
633
+
634
+ The model also appears to align naturally with AI-assisted manifest
635
+ generation. Surface and shape assertions can often be inferred from
636
+ static descriptions such as OpenAPI documents, ALPS profiles, API
637
+ Stories, or source scanning. Workflow and governance assertions usually
638
+ require deeper domain understanding and runtime knowledge.
639
+
640
+ ## Additive manifests and long-term evolution
641
+
642
+ TRAM manifests also compose well operationally.
643
+
644
+ New API features can ship with new manifests without requiring older
645
+ manifests to be rewritten. Existing manifests remain as cumulative
646
+ regression coverage.
647
+
648
+ For example:
649
+
650
+ ``` text
651
+ surface manifest
652
+ + shape manifest
653
+ + safe behavior manifest
654
+ + unsafe behavior manifest
655
+ + workflow manifests
656
+ + governance manifests
657
+ + feature-specific manifests
658
+ ```
659
+
660
+ A pipeline may simply execute all manifests as part of deployment
661
+ validation:
662
+
663
+ ``` bash
664
+ tram manifests/*.json
665
+ ```
666
+
667
+ This allows manifests to evolve incrementally alongside the API itself.
668
+
669
+ Viewed this way, TRAM manifests become not only executable verification
670
+ artifacts, but also a growing behavioral record of the system over time.
671
+
672
+ As manifests accumulate across releases, they begin to function as a
673
+ historical operational record describing how the observable behavior of
674
+ the system evolved over time.
675
+
676
+ ## From behavioral models to behavioral traceability
677
+
678
+ The layered model described in this document organizes observable API
679
+ behavior into progressively richer concerns. As these layers emerged
680
+ during the development of TRAM, another pattern became apparent.
681
+ Executable assertions rarely appeared in isolation. Most could be traced
682
+ back to an earlier behavioral description in an API Story, an ALPS
683
+ profile, an OpenAPI description, or a governance rule.
684
+
685
+ That observation raises an important question:
686
+
687
+ > As behavioral intent is translated into successive design and
688
+ > implementation artifacts, how can we determine whether that intent has
689
+ > been preserved?
690
+
691
+ The **Behavioral Traceability Matrix (BTM)** emerged as one answer to
692
+ that question.
693
+
694
+ The BTM is not another behavioral layer or another design artifact. It records the relationship between behavioral objectives and the artifacts that describe, implement, execute, and verify them.
695
+
696
+ ## Behavioral objectives and traceability
697
+
698
+ Organizing assertions into behavioral layers improves readability and
699
+ maintenance, but it also exposes a broader opportunity. Each executable
700
+ assertion represents a behavioral objective that can often be traced
701
+ back through earlier design artifacts.
702
+
703
+ Rather than tracing documents alone, the Behavioral Traceability Matrix
704
+ treats the behavioral objective as the primary unit of identity.
705
+ Individual artifacts evolve over time. APIs change, implementations are
706
+ replaced, and protocols mature. The intended behavior provides the
707
+ stable thread that connects those translations.
708
+
709
+ A simple Behavioral Traceability Matrix might look like this:
710
+
711
+ | Behaviorial Objective | API Story | ALPS | OpenAPI | TRAM | Evidence |
712
+ |----------|-----------|------|----------|------|----------|
713
+ | BH-001 List tasks | §2.1 | `listTasks` | `GET /tasks` | `surface-01.json` | PASS |
714
+ | BH-002 Create task | §2.2 | `createTask` | `POST /tasks` | `unsafe-03.json` | PASS |
715
+ | BH-003 Complete task | §2.3 | `completeTask` | `PUT /tasks/{id}/status` | `workflow-02.json` | PASS |
716
+
717
+ Notice that every row describes a single behavioral objective rather than a resource, endpoint, or document. The behavioral objective becomes the stable identity that survives each translation.
718
+
719
+ Each row follows a single behavioral objective across successive
720
+ translations. The matrix does not replace the individual artifacts; it
721
+ records their relationship. This makes it easier to identify missing
722
+ translations, incomplete implementations, or behavioral claims that lack
723
+ executable evidence.
724
+
725
+ The BTM also complements translation reports. Translation reports explain how one artifact became another. The Behavioral Traceability Matrix records where each behavioral objective appears across those artifacts.
726
+
727
+ Viewed this way, the BTM extends the ideas introduced by TRAM.
728
+ Executable assertions become behavioral models, and those models become
729
+ traceable units that connect intent, design, implementation, and
730
+ evidence.
731
+
732
+ ## Closing notes
733
+
734
+ The layers described here are intentionally exploratory rather than
735
+ prescriptive. Different systems may organize manifests differently. Some
736
+ assertions will overlap multiple layers. Other systems may discover
737
+ entirely different organizational patterns over time.
738
+
739
+ The value of the model lies less in strict categorization and more in
740
+ separating concerns clearly enough that observable system behavior
741
+ becomes easier to describe and verify.
742
+
743
+ Viewed this way, TRAM manifests become more than executable tests. They
744
+ become readable behavioral models of running systems. Combined with the
745
+ Behavioral Traceability Matrix, they also provide a way to preserve
746
+ behavioral continuity across design, implementation, and execution.
747
+
748
+ Behavioral modeling identifies what a system should do. Behavioral traceability preserves the continuity of that intent by recording where it appears throughout the lifecycle. Together they support a development process centered on
749
+ behavioral continuity rather than isolated implementation artifacts.