@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,29 @@
|
|
|
1
|
+
# TRAM 0.1.0 beta status
|
|
2
|
+
|
|
3
|
+
TRAM 0.1.0 is an initial beta release of the Test Runner for Assertion Manifests. It is intended for testing observable HTTP API behavior using declarative manifests.
|
|
4
|
+
|
|
5
|
+
## Supported environment
|
|
6
|
+
|
|
7
|
+
- Node.js 18 or later.
|
|
8
|
+
- No third-party runtime dependencies.
|
|
9
|
+
- Manifest formats `0.1` and `0.2`. Package version and manifest version are independent.
|
|
10
|
+
- CLI invocation: `tram <manifest-file> [options]`.
|
|
11
|
+
|
|
12
|
+
## Current capabilities
|
|
13
|
+
|
|
14
|
+
- Manifest validation and sequential HTTP request execution.
|
|
15
|
+
- HTTP status, header, and response-body assertions, including collection and object-map assertions.
|
|
16
|
+
- Run-scoped data generation and interpolation.
|
|
17
|
+
- Response capture and reuse in later requests (manifest `0.2`).
|
|
18
|
+
- Console results, JSON reports, and HTTP transcripts.
|
|
19
|
+
- Nonzero process exit status when a run fails.
|
|
20
|
+
|
|
21
|
+
## Limitations and security
|
|
22
|
+
|
|
23
|
+
- Header redaction in JSON reports and HTTP transcripts covers `Authorization`, `Cookie`, `Set-Cookie`, and `X-API-Key` (case-insensitive).
|
|
24
|
+
- Secrets in URLs, bodies, assertion evidence, and other header names may appear in output. Review artifacts before sharing them.
|
|
25
|
+
- HTTP responses and test results are observations of the target service; they do not establish correctness of unobservable side effects.
|
|
26
|
+
- The npm package contains the runner and selected documentation, not the sample API or sample manifests. Clone the source repository for tutorials.
|
|
27
|
+
- The beta may change in response to user feedback. Pin versions for repeatable installations.
|
|
28
|
+
|
|
29
|
+
Report problems at https://github.com/mamund/tram/issues.
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# Behavioral assertions as operational artifacts
|
|
2
|
+
|
|
3
|
+
*From scenarios to assertions in distributed and AI-assisted systems*
|
|
4
|
+
|
|
5
|
+
## APIs already have strong structural tooling
|
|
6
|
+
|
|
7
|
+
Modern API systems already have strong tooling around structure and implementation. We can generate OpenAPI descriptions, validate schemas, monitor uptime, create SDKs, and scaffold large portions of an application from prompts or examples. Much of the routine work around API construction has become increasingly automated.
|
|
8
|
+
|
|
9
|
+
At the same time, distributed systems continue to fail in ways that are not primarily structural. JSON may validate correctly while workflows drift, assumptions diverge, affordances disappear, or state transitions become inconsistent across services and clients. In practice, many operational problems emerge from disagreements about behavior rather than disagreements about syntax.
|
|
10
|
+
|
|
11
|
+
Behavioral expectations are often scattered across several places:
|
|
12
|
+
|
|
13
|
+
* prose documentation
|
|
14
|
+
* automated test suites
|
|
15
|
+
* monitoring dashboards
|
|
16
|
+
* client-side assumptions
|
|
17
|
+
* tribal knowledge within teams
|
|
18
|
+
|
|
19
|
+
The result is fragmentation. The system may expose a formally valid interface while the operational meaning of the system becomes harder to inspect directly.
|
|
20
|
+
|
|
21
|
+
## From narrative scenarios to structured assertions
|
|
22
|
+
|
|
23
|
+
TRAM (Test Runner for Assertion Manifests) explores a different approach. Instead of treating behavioral expectations as details embedded inside code or narrative scenarios, TRAM treats assertions themselves as portable operational artifacts.
|
|
24
|
+
|
|
25
|
+
This idea sits within a familiar lineage. Behavior-Driven Development (BDD) helped shift attention away from implementation details and toward observable system behavior. A typical BDD scenario might read:
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
Given a task exists
|
|
29
|
+
When the status is updated
|
|
30
|
+
Then the task becomes completed
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The value of this style was clarity. Teams could discuss expected behavior in a shared language that connected domain intent to executable verification.
|
|
34
|
+
|
|
35
|
+
TRAM moves in a slightly different direction. The focus shifts from narrative scenarios toward structured assertions:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"path": "$.status",
|
|
40
|
+
"equals": "completed"
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The important distinction is not the use of JSON instead of prose. The larger shift is that assertions become directly inspectable as independent operational statements. They can be reused, grouped, queried, analyzed, or executed without being tightly coupled to a particular test script or implementation framework.
|
|
45
|
+
|
|
46
|
+
In this model, the manifest becomes a place where operational expectations are expressed explicitly. Assertions may describe:
|
|
47
|
+
|
|
48
|
+
* valid state transitions
|
|
49
|
+
* expected response structures
|
|
50
|
+
* affordance presence
|
|
51
|
+
* collection invariants
|
|
52
|
+
* validation rules
|
|
53
|
+
* error semantics
|
|
54
|
+
* behavioral constraints
|
|
55
|
+
|
|
56
|
+
TRAM now organizes behavioral verification into six progressive layers:
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
Level 0 — Surface
|
|
60
|
+
Level 1 — Shape
|
|
61
|
+
Level 2 — Safe behavior
|
|
62
|
+
Level 3 — Unsafe behavior
|
|
63
|
+
Level 4 — Workflow
|
|
64
|
+
Level 5 — Governance
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Each layer isolates a different class of operational concern while narrowing debugging scope and preserving readable behavioral intent.
|
|
68
|
+
|
|
69
|
+
This changes the role of verification. Instead of merely asking whether a test passes, the system begins to expose the operational assumptions that govern expected behavior.
|
|
70
|
+
|
|
71
|
+
## Optional properties and behavioral contracts
|
|
72
|
+
|
|
73
|
+
The distinction between structural validation and behavioral validation becomes more visible as APIs evolve over time.
|
|
74
|
+
|
|
75
|
+
Traditional schema-oriented validation often assumes that stable representations should expose stable fields. In practice, distributed systems frequently operate with conditional representations:
|
|
76
|
+
|
|
77
|
+
* permissions may affect field visibility
|
|
78
|
+
* affordances may appear only in certain states
|
|
79
|
+
* sparse responses may omit metadata
|
|
80
|
+
* evolving systems may gradually introduce new properties
|
|
81
|
+
* runtime conditions may alter representation shape
|
|
82
|
+
|
|
83
|
+
In these environments, absence can itself be valid behavior.
|
|
84
|
+
|
|
85
|
+
Recent additions to the TRAM assertion model support optional property assertions.
|
|
86
|
+
|
|
87
|
+
Example:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"path": "$",
|
|
92
|
+
"each": {
|
|
93
|
+
"property": "description",
|
|
94
|
+
"optional": true,
|
|
95
|
+
"type": "string"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
This assertion means:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
"description" may be absent
|
|
104
|
+
if present, it must still validate as a string
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The important point is not the syntax itself. The larger implication is that behavioral correctness is no longer treated as identical to rigid structural completeness.
|
|
108
|
+
|
|
109
|
+
A missing property may still represent correct operational behavior. A present property with invalid semantics does not.
|
|
110
|
+
|
|
111
|
+
The distinction between representation shape and semantic legitimacy becomes increasingly important in evolving systems.
|
|
112
|
+
|
|
113
|
+
A representation may remain structurally recognizable while violating operational expectations around:
|
|
114
|
+
|
|
115
|
+
* allowed values
|
|
116
|
+
* ranges
|
|
117
|
+
* permissions
|
|
118
|
+
* workflow constraints
|
|
119
|
+
* behavioral policies
|
|
120
|
+
|
|
121
|
+
This becomes especially important in hypermedia-oriented systems where affordances, metadata, and navigation controls may appear conditionally at runtime. Optional assertions allow manifests to model these conditional representations without collapsing into either rigid schema enforcement or loosely defined payload checking.
|
|
122
|
+
|
|
123
|
+
The result is a middle ground between exhaustive schema systems and purely ad hoc testing. Assertions remain executable and explicit while still allowing representations to evolve behaviorally over time.
|
|
124
|
+
|
|
125
|
+
## Hypermedia broadens the definition of testing
|
|
126
|
+
|
|
127
|
+
The distinction becomes more visible in hypermedia-oriented systems. Many API testing approaches assume a relatively static environment:
|
|
128
|
+
|
|
129
|
+
* known endpoints
|
|
130
|
+
* predefined workflows
|
|
131
|
+
* fixed sequences of operations
|
|
132
|
+
|
|
133
|
+
Hypermedia systems operate differently. Clients discover available actions dynamically through links, forms, and embedded controls. In these systems, behavior is exposed at runtime through affordances rather than being fully predetermined in client code.
|
|
134
|
+
|
|
135
|
+
In hypermedia-oriented systems, runtime discoverability itself becomes part of observable behavior.
|
|
136
|
+
|
|
137
|
+
Testing therefore expands beyond endpoint correctness into questions of navigability, affordance exposure, and runtime coordination surfaces.
|
|
138
|
+
|
|
139
|
+
Verification now includes questions such as:
|
|
140
|
+
|
|
141
|
+
* Are expected affordances present?
|
|
142
|
+
* Can clients discover valid transitions?
|
|
143
|
+
* Are navigation surfaces exposed consistently?
|
|
144
|
+
* Do runtime constraints appear correctly?
|
|
145
|
+
|
|
146
|
+
The attached TRAM manifest already reflects this orientation. One assertion verifies the presence of a `_links` object at the API root along with a discoverable `taskList` affordance. Another verifies that task collections expose valid state values across all returned items.
|
|
147
|
+
|
|
148
|
+
Recent additions to the assertion model also support object-map traversal (`eachProperty`), allowing manifests to validate affordance-oriented structures such as hypermedia link maps without introducing scripting or custom matcher code.
|
|
149
|
+
|
|
150
|
+
For example:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"path": "$._links",
|
|
155
|
+
"eachProperty": {
|
|
156
|
+
"hasProperties": ["href", "method"]
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
TRAM distinguishes between:
|
|
162
|
+
|
|
163
|
+
* `each` for arrays
|
|
164
|
+
* `eachProperty` for object maps
|
|
165
|
+
|
|
166
|
+
It also distinguishes between:
|
|
167
|
+
|
|
168
|
+
* `path` for structural traversal
|
|
169
|
+
* `property` for scalar leaf assertions
|
|
170
|
+
|
|
171
|
+
This allows manifests to express nested affordance validation while preserving declarative readability.
|
|
172
|
+
|
|
173
|
+
Optional assertions also work inside nested object-map traversal.
|
|
174
|
+
|
|
175
|
+
Example:
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"path": "$._links",
|
|
180
|
+
"eachProperty": {
|
|
181
|
+
"path": "$.title",
|
|
182
|
+
"optional": true,
|
|
183
|
+
"type": "string"
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
This allows manifests to express behavioral expectations around conditional affordance metadata while preserving declarative structure and readable operational intent.
|
|
189
|
+
|
|
190
|
+
These checks move beyond endpoint availability. They verify aspects of runtime coordination and discoverability that are especially important in adaptive or agent-oriented systems.
|
|
191
|
+
|
|
192
|
+
## Generated systems increase the value of behavioral clarity
|
|
193
|
+
|
|
194
|
+
This becomes increasingly relevant as generated code becomes more common. AI-assisted development can accelerate implementation work substantially. At the same time, implementation itself becomes a less stable coordination surface. Different generated components may satisfy structural requirements while still drifting behaviorally over time.
|
|
195
|
+
|
|
196
|
+
As implementation becomes easier to generate, operational behavior becomes more important as a durable point of reference.
|
|
197
|
+
|
|
198
|
+
Assertion manifests offer one possible stabilizing layer. They provide a shared behavioral reference point that can be inspected by:
|
|
199
|
+
|
|
200
|
+
* developers
|
|
201
|
+
* architects
|
|
202
|
+
* CI systems
|
|
203
|
+
* monitoring tools
|
|
204
|
+
* AI assistants
|
|
205
|
+
|
|
206
|
+
Recent workflow-oriented manifest patterns also allow TRAM assertions to model accumulated operational narratives rather than isolated endpoint checks.
|
|
207
|
+
|
|
208
|
+
TRAM models these workflows through declarative sequencing rather than embedded scripting. Requests execute sequentially in manifest order while preserving readable operational intent as a first-class artifact.
|
|
209
|
+
|
|
210
|
+
A workflow manifest may:
|
|
211
|
+
|
|
212
|
+
* create resources
|
|
213
|
+
* retrieve intermediate state
|
|
214
|
+
* apply mutations
|
|
215
|
+
* verify accumulated final state
|
|
216
|
+
|
|
217
|
+
This allows operational continuity itself to become directly inspectable.
|
|
218
|
+
|
|
219
|
+
This is not primarily about replacing human judgment with automation. The manifest creates a visible representation of expected operational behavior that humans and machines can collaborate around. Assertions become reviewable objects rather than hidden details buried inside application code or testing frameworks.
|
|
220
|
+
|
|
221
|
+
Recent additions to the TRAM runtime also distinguish between:
|
|
222
|
+
|
|
223
|
+
* manifest authoring failures
|
|
224
|
+
* request/runtime failures
|
|
225
|
+
* behavioral assertion failures
|
|
226
|
+
|
|
227
|
+
Malformed manifests now fail validation before any HTTP requests execute. This preserves a stronger boundary between operational intent and runtime behavior. A malformed manifest represents an authoring defect rather than an API failure.
|
|
228
|
+
|
|
229
|
+
That distinction becomes increasingly important in generated systems where assertions themselves may be produced collaboratively by humans and AI assistants. Validation helps preserve the manifest as a trustworthy operational artifact rather than treating it as an opaque execution script.
|
|
230
|
+
|
|
231
|
+
That collaborative aspect matters. Many software artifacts are optimized either for machines or for humans, but not both simultaneously. Assertion manifests occupy an interesting middle space. They remain executable while still exposing operational intent in a relatively direct form.
|
|
232
|
+
|
|
233
|
+
## Behavior as a first-class operational layer
|
|
234
|
+
|
|
235
|
+
The broader architectural question underneath TRAM is whether behavior itself should become a first-class operational layer in distributed systems. APIs already expose structural contracts through schemas and interface descriptions. Hypermedia systems expose runtime affordances through messages. Assertion manifests extend this progression by exposing behavioral expectations as portable, inspectable artifacts independent of implementation details.
|
|
236
|
+
|
|
237
|
+
The runtime validation model reinforces this separation by treating manifest correctness as a distinct concern from API correctness.
|
|
238
|
+
|
|
239
|
+
TRAM also supports stable run-scoped interpolation values, allowing related behavioral interactions to share state across requests without introducing custom scripting. This keeps multi-step workflows explicit, reviewable, and manifest-driven.
|
|
240
|
+
|
|
241
|
+
The layered structure also narrows debugging scope operationally.
|
|
242
|
+
|
|
243
|
+
If a workflow assertion fails at Level 4 while Levels 0–3 continue passing, the failure can often be localized to continuity, accumulation, or sequencing behavior rather than transport, representation, or isolated mutation semantics.
|
|
244
|
+
|
|
245
|
+
This approach does not replace existing testing or observability systems. Unit tests, schema validation, monitoring, and contract testing each address important concerns. TRAM explores a narrower but increasingly important space: the explicit expression of operational behavior itself.
|
|
246
|
+
|
|
247
|
+
The implementation underneath a system may evolve rapidly over time. Behavioral expectations still need to remain visible, reviewable, and stable enough for coordination to persist across teams, services, tooling, and increasingly adaptive runtime environments.
|
|
248
|
+
|
|
249
|
+
## Observations can become evidence
|
|
250
|
+
|
|
251
|
+
Behavioral verification often depends on observations made during earlier interactions. Some API behaviors produce values that are not known until runtime, such as generated identifiers or hypermedia links. TRAM's capture feature records those observed values and makes them available to later requests. This allows behavioral models to remain declarative while expressing workflows that depend on server-generated state.
|
|
252
|
+
|
|
253
|
+
Capture is an observation mechanism rather than a scripting mechanism. The manifest does not compute new values or direct control flow. Instead, it records what the API actually produced—including identifiers, affordances, and other observable values—and reuses that evidence in subsequent interactions.
|
|
254
|
+
|
|
255
|
+
In this sense, capture extends the role of assertions beyond verification alone. The manifest records observations, expresses them as executable behavior, and preserves the resulting evidence for later interactions. Observable behavior becomes a reusable operational artifact rather than a transient detail of a single request.
|
|
256
|
+
|
|
Binary file
|
|
Binary file
|