@netgreener/runtime 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.
Files changed (138) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +28 -0
  3. package/TUTORIAL.md +495 -0
  4. package/dist/aggregator.d.ts +43 -0
  5. package/dist/aggregator.js +270 -0
  6. package/dist/analyze/analyzeGate.d.ts +44 -0
  7. package/dist/analyze/analyzeGate.js +114 -0
  8. package/dist/analyze/apiOverconsumptionDetector.d.ts +13 -0
  9. package/dist/analyze/apiOverconsumptionDetector.js +75 -0
  10. package/dist/analyze/astDetectors.d.ts +38 -0
  11. package/dist/analyze/astDetectors.js +566 -0
  12. package/dist/analyze/buildResourceFindings.d.ts +34 -0
  13. package/dist/analyze/buildResourceFindings.js +86 -0
  14. package/dist/analyze/cli.d.ts +20 -0
  15. package/dist/analyze/cli.js +186 -0
  16. package/dist/analyze/cpuResourceDetectors.d.ts +35 -0
  17. package/dist/analyze/cpuResourceDetectors.js +163 -0
  18. package/dist/analyze/heuristicScan.d.ts +61 -0
  19. package/dist/analyze/heuristicScan.js +91 -0
  20. package/dist/analyze/index.d.ts +15 -0
  21. package/dist/analyze/index.js +15 -0
  22. package/dist/analyze/loadTypescript.d.ts +8 -0
  23. package/dist/analyze/loadTypescript.js +23 -0
  24. package/dist/analyze/memoryIoDetectors.d.ts +15 -0
  25. package/dist/analyze/memoryIoDetectors.js +68 -0
  26. package/dist/analyze/preferAstDetectors.d.ts +18 -0
  27. package/dist/analyze/preferAstDetectors.js +91 -0
  28. package/dist/analyze/projectScan.d.ts +19 -0
  29. package/dist/analyze/projectScan.js +115 -0
  30. package/dist/analyze/resourceAdmission.d.ts +33 -0
  31. package/dist/analyze/resourceAdmission.js +91 -0
  32. package/dist/analyze/resourceFindingCandidate.d.ts +61 -0
  33. package/dist/analyze/resourceFindingCandidate.js +75 -0
  34. package/dist/analyze/retryAmplificationDetector.d.ts +11 -0
  35. package/dist/analyze/retryAmplificationDetector.js +55 -0
  36. package/dist/analyze/schemas/resource-finding.schema.json +352 -0
  37. package/dist/analyze/serviceDiscovery.d.ts +66 -0
  38. package/dist/analyze/serviceDiscovery.js +210 -0
  39. package/dist/analyze/unboundedParallelismDetector.d.ts +11 -0
  40. package/dist/analyze/unboundedParallelismDetector.js +57 -0
  41. package/dist/analyze/validateResourceFinding.d.ts +19 -0
  42. package/dist/analyze/validateResourceFinding.js +46 -0
  43. package/dist/bullmq.d.ts +33 -0
  44. package/dist/bullmq.js +106 -0
  45. package/dist/cli/helpText.d.ts +8 -0
  46. package/dist/cli/helpText.js +99 -0
  47. package/dist/cli/netgreener.d.ts +12 -0
  48. package/dist/cli/netgreener.js +65 -0
  49. package/dist/collectorIpc.d.ts +28 -0
  50. package/dist/collectorIpc.js +189 -0
  51. package/dist/collectorMetadata.d.ts +15 -0
  52. package/dist/collectorMetadata.js +33 -0
  53. package/dist/config.d.ts +41 -0
  54. package/dist/config.js +97 -0
  55. package/dist/contract/index.d.ts +1 -0
  56. package/dist/contract/index.js +1 -0
  57. package/dist/contract/observation-envelope.schema.json +331 -0
  58. package/dist/contract/observation-protobuf-view.schema.json +773 -0
  59. package/dist/contract/observation-v1.d.mts +42 -0
  60. package/dist/contract/observation-v1.mjs +555 -0
  61. package/dist/contract/observationIdentity.d.ts +11 -0
  62. package/dist/contract/observationIdentity.js +48 -0
  63. package/dist/contract/observationProjection.d.ts +3 -0
  64. package/dist/contract/observationProjection.js +29 -0
  65. package/dist/contract/validate.d.ts +20 -0
  66. package/dist/contract/validate.js +227 -0
  67. package/dist/dogfood/mp3WorkerGates.d.ts +54 -0
  68. package/dist/dogfood/mp3WorkerGates.js +86 -0
  69. package/dist/dogfood/retainDryRunArtifact.d.ts +45 -0
  70. package/dist/dogfood/retainDryRunArtifact.js +103 -0
  71. package/dist/dogfood/tenantDogfoodGates.d.ts +76 -0
  72. package/dist/dogfood/tenantDogfoodGates.js +206 -0
  73. package/dist/exporter.d.ts +56 -0
  74. package/dist/exporter.js +304 -0
  75. package/dist/express.d.ts +44 -0
  76. package/dist/express.js +118 -0
  77. package/dist/externalApiMeter.d.ts +72 -0
  78. package/dist/externalApiMeter.js +1167 -0
  79. package/dist/fastify.d.ts +53 -0
  80. package/dist/fastify.js +148 -0
  81. package/dist/index.d.ts +32 -0
  82. package/dist/index.js +31 -0
  83. package/dist/n4/deploymentMatrix.d.ts +22 -0
  84. package/dist/n4/deploymentMatrix.js +57 -0
  85. package/dist/n4/missingnessInventory.d.ts +22 -0
  86. package/dist/n4/missingnessInventory.js +72 -0
  87. package/dist/nest.d.ts +42 -0
  88. package/dist/nest.js +87 -0
  89. package/dist/processResources.d.ts +28 -0
  90. package/dist/processResources.js +31 -0
  91. package/dist/processRuntime.d.ts +35 -0
  92. package/dist/processRuntime.js +96 -0
  93. package/dist/requestContext.d.ts +21 -0
  94. package/dist/requestContext.js +33 -0
  95. package/dist/runtime.d.ts +60 -0
  96. package/dist/runtime.js +289 -0
  97. package/dist/runtimeHealth.d.ts +35 -0
  98. package/dist/runtimeHealth.js +121 -0
  99. package/dist/serverlessHints.d.ts +26 -0
  100. package/dist/serverlessHints.js +52 -0
  101. package/dist/tenantContext.d.ts +78 -0
  102. package/dist/tenantContext.js +226 -0
  103. package/dist/tenantDefaults.d.ts +9 -0
  104. package/dist/tenantDefaults.js +9 -0
  105. package/dist/types.d.ts +131 -0
  106. package/dist/types.js +2 -0
  107. package/dist/uploader.d.ts +23 -0
  108. package/dist/uploader.js +52 -0
  109. package/dist/windowId.d.ts +2 -0
  110. package/dist/windowId.js +7 -0
  111. package/examples/analyze-manifest.mjs +30 -0
  112. package/examples/bullmq-live-smoke.mjs +178 -0
  113. package/examples/bullmq-mp3-worker-gate.mjs +237 -0
  114. package/examples/express-dry-run.mjs +72 -0
  115. package/examples/process-mp3-restart-gate.mjs +135 -0
  116. package/examples/retain-dry-run.mjs +110 -0
  117. package/examples/tenant-dogfood.mjs +269 -0
  118. package/fixtures/analyze-sample/architectureNoise.ts +13 -0
  119. package/fixtures/analyze-sample/cpuHotPaths.ts +27 -0
  120. package/fixtures/analyze-sample/fanOutClient.ts +15 -0
  121. package/fixtures/analyze-sample/inferenceHotPaths.ts +22 -0
  122. package/fixtures/analyze-sample/memoryIoHotPaths.ts +21 -0
  123. package/fixtures/analyze-sample/modelLoadHotPaths.ts +11 -0
  124. package/fixtures/analyze-sample/nestedLookup.ts +15 -0
  125. package/fixtures/analyze-sample/retryClient.ts +10 -0
  126. package/fixtures/analyze-sample/securitySmell.ts +8 -0
  127. package/fixtures/analyze-sample/server.ts +11 -0
  128. package/fixtures/analyze-sample/styleOnly.ts +7 -0
  129. package/fixtures/analyze-sample/worker.ts +4 -0
  130. package/fixtures/dual-view-projection.v1.json +53 -0
  131. package/fixtures/identity-preimages.v1.json +42 -0
  132. package/fixtures/mp2_shadow_digest_golden.v1.json +47 -0
  133. package/fixtures/projection-batch-document.v1.json +170 -0
  134. package/fixtures/projection-batch.v1.json +9 -0
  135. package/fixtures/python_reference_shapes.md +24 -0
  136. package/fixtures/session_metadata_runtime_v0.json +120 -0
  137. package/fixtures/session_metadata_with_tenant.json +85 -0
  138. package/package.json +137 -0
@@ -0,0 +1,53 @@
1
+ {
2
+ "schema_name": "netgreener.observation.dual_view_golden.v1",
3
+ "contract_status": "observation_source_admitted_draft",
4
+ "purpose": "Cross-language dual-view projection parity (semantic envelope → protobuf JSON view). Additive validators only; no upload or TCK default flip.",
5
+ "rules": "project via admitted enum/shape mapping; digest with observation projection canonicalizer (sort keys; omit null; comma-colon JSON)",
6
+ "semantic_envelope": {
7
+ "schema_name": "netgreener.observation.v1",
8
+ "schema_version": 1,
9
+ "contract_status": "mp0_draft",
10
+ "batch_id": "bat_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
11
+ "batch_sequence": "1",
12
+ "emitted_at": "2026-09-12T15:00:00Z",
13
+ "source": {
14
+ "language": "python",
15
+ "runtime_name": "cpython",
16
+ "runtime_version": "3.11.9",
17
+ "adapter_name": "netgreener-runtime",
18
+ "adapter_version": "0.1.0",
19
+ "runtime_instance_id": "rti_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
20
+ "capability_ids": ["CAP-R1"],
21
+ "deployment_mode": "local"
22
+ },
23
+ "routing": {
24
+ "project_id": 42,
25
+ "workload_id": "api",
26
+ "service_name": "api"
27
+ },
28
+ "privacy": {
29
+ "content_capture": "none",
30
+ "dimension_policy": "allowlist",
31
+ "route_policy": "template_or_unknown",
32
+ "dropped_dimension_count": 0
33
+ },
34
+ "events": [
35
+ {
36
+ "event_id": "evt_cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
37
+ "sequence": "1",
38
+ "wall_time_unix_nano": "1787500805000000000",
39
+ "monotonic_time_ns": "5000000000",
40
+ "clock_source": "runtime_monotonic",
41
+ "record_type": "adapter_health",
42
+ "facts": {
43
+ "component": "adapter",
44
+ "status": "ok",
45
+ "reason_codes": [],
46
+ "counters": { "queue_depth": 0 }
47
+ }
48
+ }
49
+ ]
50
+ },
51
+ "expected_projection_digest": "sha256:c0000c0e7698a55a6907eb3f4d8061e22c95557557006fc5904eacd26a57a41d",
52
+ "expected_byte_length": 1108
53
+ }
@@ -0,0 +1,42 @@
1
+ {
2
+ "schema_name": "netgreener.observation.identity_preimages.v1",
3
+ "contract_status": "observation_source_admitted_draft",
4
+ "algorithm": "sha256(length_prefixed(domain, components...)); 4-byte big-endian lengths",
5
+ "cases": [
6
+ {
7
+ "name": "runtime_instance_fixed_nonce",
8
+ "domain": "netgreener.observation.v1/runtime-instance",
9
+ "components": [
10
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
11
+ ],
12
+ "expected_id": "rti_e83199561ca1184e69dd68079f3859da717e38033711b63fde959422168ebd5e"
13
+ },
14
+ {
15
+ "name": "event_seq_1",
16
+ "domain": "netgreener.observation.v1/event",
17
+ "components": [
18
+ "rti_e83199561ca1184e69dd68079f3859da717e38033711b63fde959422168ebd5e",
19
+ "1"
20
+ ],
21
+ "expected_id": "evt_05e147d2c9270fb09b1b9caf05922d3fd18face18c7c3bc5c6d21af3df8fa1fc"
22
+ },
23
+ {
24
+ "name": "batch_seq_1",
25
+ "domain": "netgreener.observation.v1/batch",
26
+ "components": [
27
+ "rti_e83199561ca1184e69dd68079f3859da717e38033711b63fde959422168ebd5e",
28
+ "1"
29
+ ],
30
+ "expected_id": "bat_fd9c302bcb34cc281e44766798e0043577cb691dba223e63e99092d045931829"
31
+ },
32
+ {
33
+ "name": "runtime_window_close_1",
34
+ "domain": "netgreener.observation.v1/runtime-window",
35
+ "components": [
36
+ "rti_eb023154e6299b5e607a3e467fcd96eaf844730fe4fcf3a3543580b2e1f7185e",
37
+ "1"
38
+ ],
39
+ "expected_id": "rtw_22e5fb5c15ef2a50f6d7fe742cd62fe7ca61e53bc40606aa4a90b952556e1e64"
40
+ }
41
+ ]
42
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "schema_name": "netgreener.mp2.shadow_digest_golden.v1",
3
+ "schema_version": 1,
4
+ "purpose": "Cross-language canonical payload digests for NETGREENER_MP2_SHADOW_COMPARE. Digest-only; no dual-POST or upload cutover.",
5
+ "algorithm": "sha256",
6
+ "encoding": "utf-8",
7
+ "canonical_json": {
8
+ "ensure_ascii": false,
9
+ "separators": [",", ":"],
10
+ "sort_keys": true
11
+ },
12
+ "cases": [
13
+ {
14
+ "id": "run_session_window_minimal",
15
+ "kind": "run_session_window",
16
+ "payload": {
17
+ "project_id": 1,
18
+ "runtime_window_id": "rtw_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
19
+ "start_time": "2026-09-15T00:00:00.000Z",
20
+ "end_time": "2026-09-15T00:05:00.000Z",
21
+ "server_name": null,
22
+ "energy_kwh": null,
23
+ "session_metadata": {
24
+ "service_runtime_v0": {
25
+ "framework": "express",
26
+ "window_seconds": 60
27
+ }
28
+ }
29
+ },
30
+ "payload_sha256": "53e1bae2966f7d7f0739c9002ca110dfecb13e74c0c7838e8d687122f46f3e17"
31
+ },
32
+ {
33
+ "id": "observation_batch_minimal",
34
+ "kind": "observation_batch",
35
+ "payload": {
36
+ "schema_name": "netgreener.observation.v1",
37
+ "schema_version": 1,
38
+ "batch_id": "bat_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
39
+ "events": [],
40
+ "routing": {
41
+ "project_id": 1
42
+ }
43
+ },
44
+ "payload_sha256": "700e24823469d384d57e9efd74fac5652a87804b5e7fa570fa44e67eba4d7808"
45
+ }
46
+ ]
47
+ }
@@ -0,0 +1,170 @@
1
+ {
2
+ "protocol_major": 1,
3
+ "protocol_minor": 1,
4
+ "batch_id": "bat_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
5
+ "batch_sequence": "9007199254740993",
6
+ "emitted_at": "2026-09-13T12:00:01Z",
7
+ "source": {
8
+ "language": "python",
9
+ "runtime_name": "cpython",
10
+ "runtime_version": "3.11.0",
11
+ "adapter_name": "fixture-adapter",
12
+ "adapter_version": "0.0.0",
13
+ "runtime_instance_id": "rti_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
14
+ "capability_ids": [
15
+ "CAP-R1",
16
+ "CAP-R2",
17
+ "CAP-R3",
18
+ "CAP-R4",
19
+ "CAP-R5",
20
+ "CAP-R6"
21
+ ],
22
+ "deployment_mode": "DEPLOYMENT_MODE_LOCAL"
23
+ },
24
+ "routing": {
25
+ "organization_id": "9007199254740992",
26
+ "project_id": "9007199254740993",
27
+ "workload_id": "fixture-workload",
28
+ "service_name": "fixture-service",
29
+ "environment": "fixture"
30
+ },
31
+ "privacy": {
32
+ "content_capture": "CONTENT_CAPTURE_NONE",
33
+ "dimension_policy": "DIMENSION_POLICY_ALLOWLIST",
34
+ "route_policy": "ROUTE_POLICY_TEMPLATE_OR_UNKNOWN",
35
+ "dropped_dimension_count": "0"
36
+ },
37
+ "window": {
38
+ "runtime_window_id": "rtw_cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
39
+ "state": "WINDOW_STATE_CLOSED",
40
+ "start_time": "2026-09-13T12:00:00Z",
41
+ "end_time": "2026-09-13T12:00:01Z"
42
+ },
43
+ "events": [
44
+ {
45
+ "event_id": "evt_1111111111111111111111111111111111111111111111111111111111111111",
46
+ "sequence": "1",
47
+ "wall_time_unix_nano": "1789300800001000000",
48
+ "monotonic_time_ns": "1001000000",
49
+ "clock_source": "CLOCK_SOURCE_PROCESS_MONOTONIC",
50
+ "clock_epoch_id": "fixture-clock-1",
51
+ "execution_id": "fixture-execution-1",
52
+ "operation_event": {
53
+ "operation": {
54
+ "kind": "OPERATION_KIND_TASK",
55
+ "unit_type": "OPERATION_UNIT_TASK",
56
+ "name": "fixture.task.live",
57
+ "identity_source": "IDENTITY_SOURCE_DECLARED"
58
+ },
59
+ "phase": "OPERATION_PHASE_FINISH",
60
+ "outcome": "OUTCOME_OK",
61
+ "duration_ns": "0"
62
+ }
63
+ },
64
+ {
65
+ "event_id": "evt_2222222222222222222222222222222222222222222222222222222222222222",
66
+ "sequence": "2",
67
+ "wall_time_unix_nano": "1789300800002000000",
68
+ "monotonic_time_ns": "1002000000",
69
+ "clock_source": "CLOCK_SOURCE_PROCESS_MONOTONIC",
70
+ "clock_epoch_id": "fixture-clock-1",
71
+ "runtime_window_id": "rtw_cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
72
+ "operation_summary": {
73
+ "operation": {
74
+ "kind": "OPERATION_KIND_TASK",
75
+ "unit_type": "OPERATION_UNIT_TASK",
76
+ "name": "fixture.task.summary",
77
+ "identity_source": "IDENTITY_SOURCE_DECLARED"
78
+ },
79
+ "calls": "23",
80
+ "errors": "0",
81
+ "duration_ns_sum": "1000000000",
82
+ "duration_ns_max": "100000000",
83
+ "concurrency_max": 4
84
+ }
85
+ },
86
+ {
87
+ "event_id": "evt_3333333333333333333333333333333333333333333333333333333333333333",
88
+ "sequence": "3",
89
+ "wall_time_unix_nano": "1789300800003000000",
90
+ "monotonic_time_ns": "1003000000",
91
+ "clock_source": "CLOCK_SOURCE_PROCESS_MONOTONIC",
92
+ "clock_epoch_id": "fixture-clock-1",
93
+ "external_call": {
94
+ "parent_operation_event_id": "evt_1111111111111111111111111111111111111111111111111111111111111111",
95
+ "provider": "fixture-provider",
96
+ "service": "fixture-api",
97
+ "operation": "fixture.operation",
98
+ "destination_domain": "api.example.invalid",
99
+ "attempts": "2",
100
+ "errors": "1",
101
+ "duration_ns": "80000",
102
+ "usage": [
103
+ {
104
+ "unit": "input_tokens",
105
+ "value": "0",
106
+ "source": "USAGE_SOURCE_PROVIDER_RESPONSE"
107
+ },
108
+ {
109
+ "unit": "output_tokens",
110
+ "value": "18446744073709551615",
111
+ "source": "USAGE_SOURCE_PROVIDER_RESPONSE"
112
+ }
113
+ ]
114
+ }
115
+ },
116
+ {
117
+ "event_id": "evt_4444444444444444444444444444444444444444444444444444444444444444",
118
+ "sequence": "4",
119
+ "wall_time_unix_nano": "1789300800004000000",
120
+ "monotonic_time_ns": "1004000000",
121
+ "clock_source": "CLOCK_SOURCE_PROCESS_MONOTONIC",
122
+ "clock_epoch_id": "fixture-clock-1",
123
+ "resource_sample": {
124
+ "scope": "RESOURCE_SCOPE_DEVICE",
125
+ "sample_kind": "SAMPLE_KIND_SNAPSHOT",
126
+ "subject_id": "fixture-gpu-0",
127
+ "measurements": [
128
+ {
129
+ "name": "MEASUREMENT_NAME_GPU_ENERGY",
130
+ "value": "0.125000000001",
131
+ "unit": "MEASUREMENT_UNIT_J",
132
+ "temporality": "TEMPORALITY_DELTA",
133
+ "source": "fixture-device-counter",
134
+ "coverage": "0.999999999999",
135
+ "counter_epoch_id": "fixture-counter-1"
136
+ },
137
+ {
138
+ "name": "MEASUREMENT_NAME_GPU_UTILIZATION",
139
+ "value": "0",
140
+ "unit": "MEASUREMENT_UNIT_RATIO",
141
+ "temporality": "TEMPORALITY_GAUGE",
142
+ "source": "fixture-device-gauge",
143
+ "coverage": "1"
144
+ }
145
+ ]
146
+ }
147
+ },
148
+ {
149
+ "event_id": "evt_5555555555555555555555555555555555555555555555555555555555555555",
150
+ "sequence": "5",
151
+ "wall_time_unix_nano": "1789300800005000000",
152
+ "monotonic_time_ns": "1005000000",
153
+ "clock_source": "CLOCK_SOURCE_PROCESS_MONOTONIC",
154
+ "clock_epoch_id": "fixture-clock-1",
155
+ "adapter_health": {
156
+ "component": "HEALTH_COMPONENT_ADAPTER",
157
+ "status": "HEALTH_STATUS_DEGRADED",
158
+ "reason_codes": [
159
+ "FIXTURE_COUNTER_LIMIT"
160
+ ],
161
+ "counters": {
162
+ "dropped_events": "18446744073709551615",
163
+ "retries": "0",
164
+ "queue_depth": "0"
165
+ }
166
+ }
167
+ }
168
+ ],
169
+ "experiment_note": "fixture-all-records"
170
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "schema_name": "netgreener.observation.projection_golden.v1",
3
+ "contract_status": "observation_source_admitted_draft",
4
+ "fixture": "observation/v1/vectors/projection-batch-document.v1.json",
5
+ "rules": "sort object keys; preserve array order; omit null; UTF-8 JSON separators comma-colon",
6
+ "expected_digest": "sha256:9eeb66c0283c03dadae5579274e4b550593d835d4aac3aca7add588d851408b7",
7
+ "byte_length": 4326,
8
+ "note": "Document admitted beside this golden; planning bindings fixture remains the historical source. Regenerate when schemas/v1 view is derived from admitted Protobuf."
9
+ }
@@ -0,0 +1,24 @@
1
+ # Legacy Python compatibility shapes (read-only)
2
+
3
+ These fixtures mirror fields produced by the current Python service runtime and
4
+ accepted by the existing API. They are migration fixtures, not the cross-language
5
+ specification. MP0 artifacts in `netgreener_contracts` will define the stable contract;
6
+ Python and Node must both conform without copying one implementation's debt.
7
+
8
+ | Block | Python origin (reference only) |
9
+ |-------|--------------------------------|
10
+ | `service_runtime_v0` | `netgreener_cli/netgreener/service_runtime_v0.py` → `build_v0` |
11
+ | `external_api_v0` | `netgreener_cli/netgreener/external_api_meter.py` → `build_v0` (+ `by_model`) |
12
+ | `measurement_provenance` / evidence | CLI/API evidence grade helpers (`r9_v0`) |
13
+ | Upload | `POST /api/v1/runsessions/` with `session_metadata` |
14
+
15
+ Legacy Node compatibility payloads use adapter identifiers such as:
16
+
17
+ - `express_middleware`
18
+ - `fastify_middleware`
19
+ - `node_process`
20
+ - `bullmq_adapter` (later)
21
+
22
+ Existing Python identifiers remain readable during migration: `asgi_middleware`,
23
+ `outbound_http`, and the current Celery/collector strings. The shared collector and
24
+ Observation v1 naming rules remain an MP0/MP2 decision.
@@ -0,0 +1,120 @@
1
+ {
2
+ "emitter": "node",
3
+ "schema_note": "Legacy compatibility fixture for Node HTTP runtime flushes. It mirrors current Python service_runtime_v0 / external_api_v0 consumers but is not the MP0 cross-language contract.",
4
+ "run_context": {
5
+ "deploy_environment": "staging",
6
+ "client": "netgreener_node_runtime",
7
+ "release_tag": "example-1.0.0"
8
+ },
9
+ "service_runtime_v0": {
10
+ "framework": "express",
11
+ "collector": "express_middleware",
12
+ "window_seconds": 60.0,
13
+ "attribution": "cpu_share",
14
+ "accuracy": "trend",
15
+ "units": [
16
+ {
17
+ "service_unit": "GET /health",
18
+ "unit_type": "http_route",
19
+ "calls": 12,
20
+ "errors": 0,
21
+ "cpu_seconds_total": 0.04,
22
+ "energy_kwh": 0.0000012,
23
+ "carbon_g": 0.0003,
24
+ "duration_ms": {
25
+ "avg": 8.5,
26
+ "max": 22.0
27
+ }
28
+ },
29
+ {
30
+ "service_unit": "POST /v1/predict",
31
+ "unit_type": "http_route",
32
+ "calls": 3,
33
+ "errors": 1,
34
+ "cpu_seconds_total": 0.21,
35
+ "energy_kwh": 0.0000063,
36
+ "carbon_g": 0.0016,
37
+ "duration_ms": {
38
+ "avg": 145.0,
39
+ "max": 310.0
40
+ },
41
+ "peak_rss_kb_max": 256000
42
+ }
43
+ ],
44
+ "allocation_reconciliation_v0": {
45
+ "schema_version": 1,
46
+ "window_energy_kwh": 0.0000075,
47
+ "allocated_energy_kwh": 0.0000075,
48
+ "residual_energy_kwh": 0.0,
49
+ "tolerance_kwh": 1e-12,
50
+ "passed": true,
51
+ "scope": "endpoint_allocation_arithmetic_only",
52
+ "endpoint_capture_coverage": null,
53
+ "capture_completeness": "unknown"
54
+ }
55
+ },
56
+ "external_api_v0": {
57
+ "collector": "outbound_http",
58
+ "providers": [
59
+ {
60
+ "provider_key": "openai",
61
+ "calls": 3,
62
+ "errors": 0,
63
+ "duration_ms_avg": 820.0,
64
+ "hosts": ["api.openai.com"],
65
+ "input_tokens": 1100,
66
+ "output_tokens": 300,
67
+ "total_tokens": 1400,
68
+ "models": ["gpt-4o-mini", "gpt-4o"],
69
+ "by_model": [
70
+ {
71
+ "model": "gpt-4o-mini",
72
+ "calls": 2,
73
+ "errors": 0,
74
+ "input_tokens": 100,
75
+ "output_tokens": 50,
76
+ "total_tokens": 150
77
+ },
78
+ {
79
+ "model": "gpt-4o",
80
+ "calls": 1,
81
+ "errors": 0,
82
+ "input_tokens": 1000,
83
+ "output_tokens": 250,
84
+ "total_tokens": 1250
85
+ }
86
+ ]
87
+ }
88
+ ]
89
+ },
90
+ "measurement_provenance": {
91
+ "cpu_source": "process_cpu_time",
92
+ "memory_source": "process_rss_samples",
93
+ "energy_model": "tdp_utilization_estimate",
94
+ "gpu_scope": "none",
95
+ "gpu_source": "unavailable",
96
+ "carbon_factor": {
97
+ "value": 0.4,
98
+ "unit": "kg_co2e_per_kwh",
99
+ "source": "default_grid_factor"
100
+ },
101
+ "evidence_grades": {
102
+ "schema_version": 1,
103
+ "policy_version": "r9_v0",
104
+ "metrics": {
105
+ "local_energy": {
106
+ "metric": "local_energy",
107
+ "grade": "G1",
108
+ "reasons": ["estimated_power_tdp"]
109
+ },
110
+ "local_carbon": {
111
+ "metric": "local_carbon",
112
+ "grade": "G1",
113
+ "reasons": ["estimated_power_tdp", "default_grid_factor"]
114
+ }
115
+ },
116
+ "combined_floor_grade": "G1",
117
+ "notes": ["vendor_carbon_separate_ledger"]
118
+ }
119
+ }
120
+ }
@@ -0,0 +1,85 @@
1
+ {
2
+ "$schema": "../../schemas/tenant_attribution_v0/session_metadata.fragment.schema.json",
3
+ "schema_note": "Node parity fixture — must match fixtures/tenant_attribution_v0/session_metadata_with_tenant.json semantics.",
4
+ "emitter": "node",
5
+ "run_context": {
6
+ "deploy_environment": "production",
7
+ "client": "deeddex-api",
8
+ "release_tag": "2026.08.31",
9
+ "tenant_id": "org_7f3a9c2b",
10
+ "tenant_source": "jwt_claim:organization_id",
11
+ "tenant_label": "Acme Corp"
12
+ },
13
+ "service_runtime_v0": {
14
+ "framework": "express",
15
+ "collector": "express_middleware",
16
+ "window_seconds": 60.0,
17
+ "attribution": "cpu_share",
18
+ "accuracy": "trend",
19
+ "units": [
20
+ {
21
+ "service_unit": "POST /v1/documents/ocr",
22
+ "unit_type": "http_route",
23
+ "calls": 84,
24
+ "errors": 1,
25
+ "cpu_seconds_total": 1.2,
26
+ "energy_kwh": 0.000036,
27
+ "carbon_g": 0.009,
28
+ "duration_ms": {
29
+ "avg": 210.0,
30
+ "max": 890.0
31
+ }
32
+ }
33
+ ],
34
+ "by_tenant": {
35
+ "org_7f3a9c2b": {
36
+ "tenant_id": "org_7f3a9c2b",
37
+ "calls": 84,
38
+ "errors": 1,
39
+ "units": [
40
+ {
41
+ "service_unit": "POST /v1/documents/ocr",
42
+ "unit_type": "http_route",
43
+ "calls": 84,
44
+ "errors": 1,
45
+ "cpu_seconds_total": 1.2,
46
+ "energy_kwh": 0.000036,
47
+ "carbon_g": 0.009,
48
+ "duration_ms": {
49
+ "avg": 210.0,
50
+ "max": 890.0
51
+ }
52
+ }
53
+ ]
54
+ }
55
+ }
56
+ },
57
+ "external_api_v0": {
58
+ "collector": "outbound_http",
59
+ "providers": [
60
+ {
61
+ "provider_key": "azure_document_intelligence",
62
+ "calls": 1200,
63
+ "errors": 3,
64
+ "duration_ms_avg": 420.0,
65
+ "hosts": ["eastus.api.cognitive.microsoft.com"]
66
+ }
67
+ ],
68
+ "by_tenant": {
69
+ "org_7f3a9c2b": {
70
+ "tenant_id": "org_7f3a9c2b",
71
+ "calls": 1200,
72
+ "errors": 3,
73
+ "providers": [
74
+ {
75
+ "provider_key": "azure_document_intelligence",
76
+ "calls": 1200,
77
+ "errors": 3,
78
+ "duration_ms_avg": 420.0,
79
+ "hosts": ["eastus.api.cognitive.microsoft.com"]
80
+ }
81
+ ]
82
+ }
83
+ }
84
+ }
85
+ }