@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.
- package/CHANGELOG.md +11 -0
- package/LICENSE +15 -0
- package/README.md +996 -2
- package/bin/tram +1117 -0
- package/docs/behavioral-modeling-for-apis.md +749 -0
- package/docs/beta-status.md +29 -0
- package/docs/explainer.md +256 -0
- package/docs/images/tram-logo.png +0 -0
- package/docs/images/tram-test-run.png +0 -0
- package/docs/manifest-spec.md +1410 -0
- package/docs/quick-start.md +92 -0
- package/docs/roadmap.md +557 -0
- package/docs/tasks-api-tutorial.md +115 -0
- package/lib/assertions.js +918 -0
- package/package.json +47 -4
|
@@ -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.
|