@senad-d/observme 0.1.3 → 0.1.5
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/.env.example +4 -0
- package/CHANGELOG.md +48 -0
- package/README.md +36 -11
- package/dashboards/observme-agent-node-graphs.json +5 -5
- package/dashboards/observme-agents.json +169 -4
- package/dashboards/observme-alerts.yaml +16 -3
- package/dashboards/observme-overview.json +6 -6
- package/dashboards/observme-trace-journey.json +4 -4
- package/docs/agent-subagent-observability-requirements.md +19 -10
- package/docs/compatibility-matrix.md +21 -4
- package/docs/configuration.md +7 -2
- package/docs/extension-integration.md +20 -13
- package/docs/reference/03-pi-event-and-session-model.md +6 -6
- package/docs/reference/04-telemetry-semantic-conventions.md +39 -1
- package/docs/reference/05-otel-pipeline-and-collector.md +23 -10
- package/docs/reference/06-security-privacy-redaction.md +13 -6
- package/docs/reference/08-query-grafana-integration.md +30 -7
- package/docs/reference/09-dashboards-alerts-slos.md +132 -3
- package/docs/reference/10-testing-release-operations.md +44 -14
- package/docs/reference/11-deployment-runbooks.md +82 -5
- package/docs/reference/12-configuration-reference.md +48 -5
- package/docs/review-validation.md +17 -0
- package/examples/README.md +7 -2
- package/examples/collector.yaml +8 -8
- package/examples/integrations/subagent-runner.ts +8 -5
- package/examples/observme.yaml +3 -2
- package/package.json +14 -4
- package/src/commands/obs-agents.ts +17 -12
- package/src/commands/obs-backfill.ts +2 -2
- package/src/commands/obs-command-support.ts +2 -1
- package/src/commands/obs-cost.ts +15 -7
- package/src/commands/obs-health.ts +22 -2
- package/src/commands/obs-loki-summary.ts +4 -8
- package/src/commands/obs-session.ts +35 -28
- package/src/commands/obs-status.ts +56 -13
- package/src/commands/obs-tools.ts +19 -8
- package/src/commands/obs-trace.ts +9 -0
- package/src/commands/obs.ts +6 -1
- package/src/config/bootstrap-project-config.ts +50 -32
- package/src/config/defaults.ts +1 -2
- package/src/config/load-config.ts +270 -81
- package/src/config/project-paths.ts +318 -6
- package/src/config/query-limits.ts +10 -0
- package/src/config/schema.ts +18 -8
- package/src/config/transport-security.ts +107 -0
- package/src/config/validate.ts +88 -12
- package/src/extension.ts +2 -12
- package/src/integration.ts +6 -2
- package/src/otel/logs.ts +24 -13
- package/src/otel/metrics.ts +24 -13
- package/src/otel/otlp-endpoint.ts +41 -2
- package/src/otel/otlp-http-options.ts +11 -0
- package/src/otel/sdk.ts +155 -9
- package/src/otel/shutdown.ts +39 -11
- package/src/otel/traces.ts +34 -16
- package/src/pi/active-agent-lease.ts +101 -0
- package/src/pi/agent-tree-tracker.ts +14 -1
- package/src/pi/compatibility.ts +121 -0
- package/src/pi/event-handlers/agent-turn.ts +16 -9
- package/src/pi/event-handlers/lifecycle.ts +312 -106
- package/src/pi/event-handlers/llm.ts +17 -9
- package/src/pi/event-handlers/session-events.ts +53 -19
- package/src/pi/event-handlers/tool-bash.ts +21 -27
- package/src/pi/handler-internals.ts +16 -26
- package/src/pi/handler-runtime.ts +159 -54
- package/src/pi/handler-types.ts +40 -17
- package/src/pi/handlers.ts +12 -1
- package/src/pi/integration-api.ts +27 -15
- package/src/pi/session-correlation.ts +167 -0
- package/src/pi/subagent-spawn.ts +164 -31
- package/src/privacy/redact.ts +574 -68
- package/src/privacy/secret-patterns.ts +6 -1
- package/src/query/grafana-readiness.ts +18 -2
- package/src/query/grafana-transport.ts +150 -27
- package/src/query/grafana-url.ts +36 -0
- package/src/query/grafana.ts +4 -136
- package/src/query/loki.ts +2 -4
- package/src/query/prometheus.ts +8 -10
- package/src/query/tempo.ts +2 -4
- package/src/query/trace-link.ts +186 -0
- package/src/safety/display-bounds.ts +84 -0
- package/src/semconv/metrics.ts +7 -0
- package/src/semconv/values.ts +2 -0
|
@@ -129,9 +129,126 @@ Zero-state interpretation checklist:
|
|
|
129
129
|
- Empty failure-only Loki tables mean no matching failures in the selected range, not that the log pipeline is broken.
|
|
130
130
|
- `or vector(0)` stats must say whether zero means healthy idle/no activity or a true zero failure ratio.
|
|
131
131
|
- Optional redacted content panels can be empty when capture is disabled or when the Collector dropped content attributes by policy.
|
|
132
|
-
- Active-session estimates are approximate across process restarts
|
|
132
|
+
- Active-session estimates are approximate across process restarts and counter resets. Raw `observme_active_agents` values are lifecycle claims, not authoritative liveness after an ungraceful exit.
|
|
133
133
|
- High-cardinality execution identifiers are allowed as Loki/Tempo filter variables only and must never be introduced into Prometheus queries or panel links from aggregate panels.
|
|
134
134
|
|
|
135
|
+
### 1.3 Active-agent leased-state contract
|
|
136
|
+
|
|
137
|
+
The authoritative metric, duration, export-interval relationship, clock-skew allowance, future-timestamp horizon, convergence target, and failure-mode behavior are defined once in [`04-telemetry-semantic-conventions.md` §12.4.1](04-telemetry-semantic-conventions.md#1241-active-agent-lease-and-clock-contract). Dashboards, alerts, examples, and tests must use that contract without introducing panel-local lease or skew windows.
|
|
138
|
+
|
|
139
|
+
Operational active-agent views combine a positive `observme_active_agents` lifecycle claim with a currently valid `observme_agent_lease_expires_unixtime_seconds` value on the generated `observme_instance_id` resource label. The instance label is an internal join/deduplication key only: it must not be exposed as a dashboard variable, group, legend, URL value, or topology identity. Duplicate scrape/exporter representations of one instance count once.
|
|
140
|
+
|
|
141
|
+
Interpret active-agent states as follows:
|
|
142
|
+
|
|
143
|
+
- positive claim plus a valid current lease: active;
|
|
144
|
+
- clean-shutdown claim of zero: inactive after normal export/scrape propagation, without waiting for lease expiry;
|
|
145
|
+
- positive claim plus an expired lease: inactive stale claim, available only as a diagnostic;
|
|
146
|
+
- missing, malformed, non-finite, or pathologically future lease: inactive (fail closed);
|
|
147
|
+
- no matching series: zero-safe healthy idle/no activity when the telemetry backend itself is reachable.
|
|
148
|
+
|
|
149
|
+
A crash, `SIGKILL`, cancelled job, or lost runner therefore converges to zero within the semantic-convention bound even if the Collector continues to expose the cached raw claim. A Collector/export outage can intentionally undercount after the last delivered lease expires; use Export Health and backend reachability to distinguish that state from process termination. Clean lifecycle handling and GitHub Actions `if: always()` cleanup remain useful latency optimizations, but neither is the correctness mechanism.
|
|
150
|
+
|
|
151
|
+
### 1.3.1 Canonical active-agent PromQL
|
|
152
|
+
|
|
153
|
+
Use the following total everywhere current live-agent state is required:
|
|
154
|
+
|
|
155
|
+
```promql
|
|
156
|
+
sum(
|
|
157
|
+
max by (observme_instance_id) (
|
|
158
|
+
(observme_active_agents > 0)
|
|
159
|
+
and on (observme_instance_id)
|
|
160
|
+
(
|
|
161
|
+
(observme_agent_lease_expires_unixtime_seconds > time())
|
|
162
|
+
and
|
|
163
|
+
(observme_agent_lease_expires_unixtime_seconds <= time() + 305)
|
|
164
|
+
)
|
|
165
|
+
)
|
|
166
|
+
) or vector(0)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Both comparisons are required. The lower bound expires stale claims; the upper bound rejects leases beyond the frozen 305-second future horizon. `and on (observme_instance_id)` fails closed when the lease is absent or non-comparable, and `max by (observme_instance_id)` removes duplicate Collector/exporter/scrape replicas before the outer sum. The final `or vector(0)` makes no-series results render as zero; when Prometheus and Export Health are reachable, zero can mean healthy idle, clean shutdown, an expired claim, or a lease that failed closed.
|
|
170
|
+
|
|
171
|
+
For a bounded emitted dimension, retain that dimension in both aggregations. Grouped queries use `or on() vector(0)` so the unlabeled zero appears only when no labeled breakdown exists. Canonical role and environment breakdowns are:
|
|
172
|
+
|
|
173
|
+
```promql
|
|
174
|
+
sum by (agent_role) (
|
|
175
|
+
max by (observme_instance_id, agent_role) (
|
|
176
|
+
(observme_active_agents > 0)
|
|
177
|
+
and on (observme_instance_id)
|
|
178
|
+
(
|
|
179
|
+
(observme_agent_lease_expires_unixtime_seconds > time())
|
|
180
|
+
and
|
|
181
|
+
(observme_agent_lease_expires_unixtime_seconds <= time() + 305)
|
|
182
|
+
)
|
|
183
|
+
)
|
|
184
|
+
) or on() vector(0)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```promql
|
|
188
|
+
sum by (environment) (
|
|
189
|
+
max by (observme_instance_id, environment) (
|
|
190
|
+
(observme_active_agents > 0)
|
|
191
|
+
and on (observme_instance_id)
|
|
192
|
+
(
|
|
193
|
+
(observme_agent_lease_expires_unixtime_seconds > time())
|
|
194
|
+
and
|
|
195
|
+
(observme_agent_lease_expires_unixtime_seconds <= time() + 305)
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
) or on() vector(0)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The shipped active claim and lease currently emit `agent_role` and `environment`; they do not emit the metric label `subagent_depth`. Therefore current-active depth panels must not group by `subagent_depth`. For a compatible pipeline that actually emits the same bounded `subagent_depth` on the active claim, this is the supported depth shape:
|
|
202
|
+
|
|
203
|
+
```promql
|
|
204
|
+
sum by (subagent_depth) (
|
|
205
|
+
max by (observme_instance_id, subagent_depth) (
|
|
206
|
+
(observme_active_agents > 0)
|
|
207
|
+
and on (observme_instance_id)
|
|
208
|
+
(
|
|
209
|
+
(observme_agent_lease_expires_unixtime_seconds > time())
|
|
210
|
+
and
|
|
211
|
+
(observme_agent_lease_expires_unixtime_seconds <= time() + 305)
|
|
212
|
+
)
|
|
213
|
+
)
|
|
214
|
+
) or on() vector(0)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Do not substitute resource-derived or high-cardinality execution labels for these dimensions. Use the bounded spawn/tree metrics for depth views in the shipped dashboards until `subagent_depth` is emitted on the active signals themselves.
|
|
218
|
+
|
|
219
|
+
Raw positive lifecycle claims are diagnostic only:
|
|
220
|
+
|
|
221
|
+
```promql
|
|
222
|
+
sum(max by (observme_instance_id) (observme_active_agents > 0)) or vector(0)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Expired positive claims are diagnostic and never contribute to the live total:
|
|
226
|
+
|
|
227
|
+
```promql
|
|
228
|
+
sum(
|
|
229
|
+
max by (observme_instance_id) (
|
|
230
|
+
(observme_active_agents > 0)
|
|
231
|
+
and on (observme_instance_id)
|
|
232
|
+
(observme_agent_lease_expires_unixtime_seconds <= time())
|
|
233
|
+
)
|
|
234
|
+
) or vector(0)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Compare raw claims, expired claims, the canonical live total, and Export Health when diagnosing a producer crash or export gap. A raw-minus-live difference can also include a missing, malformed, or pathologically future lease, so it must not be labeled strictly as “expired.” Never expose `observme_instance_id` as a variable or legend in these diagnostics.
|
|
238
|
+
|
|
239
|
+
### 1.3.2 Migration from raw active-agent queries
|
|
240
|
+
|
|
241
|
+
Use this rollout order for custom dashboards, recording rules, alerts, and API consumers:
|
|
242
|
+
|
|
243
|
+
1. Deploy ObservMe producers that emit both `observme_active_agents` and `observme_agent_lease_expires_unixtime_seconds` with the same generated `observme_instance_id` resource label.
|
|
244
|
+
2. Confirm the lease metric is present and clocks are synchronized before changing consumers. A missing lease fails closed, so a mixed-version producer without the new metric will not appear in the leased total.
|
|
245
|
+
3. Replace raw `sum(observme_active_agents)`, raw role sums, and any equivalent positive-claim aggregation with the canonical total or bounded-dimension form above. Preserve the future-horizon check, instance join, deduplication, and zero-safe fallback together.
|
|
246
|
+
4. Keep raw and expired-claim queries only in panels or runbooks explicitly labeled as diagnostics. Do not use them for paging, capacity decisions, or current topology.
|
|
247
|
+
5. Keep Collector `metric_expiration` longer than the lease. Do not shorten expiration or schedule Collector restarts to correct liveness; an expired lease stops counting while the cached raw claim remains available for diagnosis.
|
|
248
|
+
6. During rollback, old raw consumers continue to see the compatibility lifecycle claim, but they regain the known ghost-agent behavior after ungraceful exits. Treat rollback as a temporary loss of crash-safe liveness semantics.
|
|
249
|
+
|
|
250
|
+
Validate the migrated consumer with live+valid, clean-shutdown, expired, missing, pathologically future, duplicate-replica, and no-series cases before production use.
|
|
251
|
+
|
|
135
252
|
## 2. Overview Dashboard
|
|
136
253
|
|
|
137
254
|
Purpose: act as the operator landing page. Users should be able to answer whether ObservMe is healthy, workload is normal, agents/subagents are healthy, spend or latency is high, and which focused dashboard to open next without scanning every raw metric series.
|
|
@@ -584,10 +701,22 @@ Severity: warning.
|
|
|
584
701
|
### Active Agents Stuck High
|
|
585
702
|
|
|
586
703
|
```promql
|
|
587
|
-
|
|
704
|
+
(
|
|
705
|
+
sum(
|
|
706
|
+
max by (observme_instance_id) (
|
|
707
|
+
(observme_active_agents > 0)
|
|
708
|
+
and on (observme_instance_id)
|
|
709
|
+
(
|
|
710
|
+
(observme_agent_lease_expires_unixtime_seconds > time())
|
|
711
|
+
and
|
|
712
|
+
(observme_agent_lease_expires_unixtime_seconds <= time() + 305)
|
|
713
|
+
)
|
|
714
|
+
)
|
|
715
|
+
) or vector(0)
|
|
716
|
+
) > 100
|
|
588
717
|
```
|
|
589
718
|
|
|
590
|
-
Severity depends on normal fleet size; tune per deployment.
|
|
719
|
+
Severity depends on normal fleet size; tune per deployment. This alert uses leased live agents, not cached raw claims.
|
|
591
720
|
|
|
592
721
|
## 12. SLOs
|
|
593
722
|
|
|
@@ -14,7 +14,9 @@ ObservMe must be tested at five levels:
|
|
|
14
14
|
|
|
15
15
|
Required areas:
|
|
16
16
|
|
|
17
|
-
- Config loading and
|
|
17
|
+
- Config loading, precedence, and active-agent lease/export-interval bounds
|
|
18
|
+
- Active-agent lease renewal, deactivation, disposal, clock movement, and clean/abrupt lifecycle behavior
|
|
19
|
+
- Canonical lease-aware PromQL, replica deduplication, and missing/expired/future lease cases
|
|
18
20
|
- Redaction patterns
|
|
19
21
|
- Hashing stability
|
|
20
22
|
- Truncation behavior
|
|
@@ -123,6 +125,29 @@ Tests:
|
|
|
123
125
|
- Prometheus metric query for token totals
|
|
124
126
|
- Grafana dashboard import validates
|
|
125
127
|
|
|
128
|
+
### 6.1 Active-agent lease integration
|
|
129
|
+
|
|
130
|
+
Run the focused cached-exporter test separately from the broad Grafana stack:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npm run test:integration:active-agent-lease
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The test starts pinned Collector and Prometheus containers, then runs real Node telemetry producers with a test-safe 2-second export interval, 10-second lease, and 1-second Prometheus scrape interval. It validates clean shutdown and `SIGTERM` first, then kills a producer with `SIGKILL` and requires all of the following:
|
|
137
|
+
|
|
138
|
+
- the raw `observme_active_agents` claim remains positive across fresh Prometheus scrapes;
|
|
139
|
+
- the canonical lease-aware count reaches zero without a shutdown event;
|
|
140
|
+
- convergence stays within the documented 10-second lease, 5-second clock-skew allowance, and one 1-second scrape interval;
|
|
141
|
+
- the Collector container identity and zero restart count remain unchanged.
|
|
142
|
+
|
|
143
|
+
The test uses no credentials or content capture. Its parent process owns bounded waits and unconditional cleanup for child processes, containers, anonymous storage, and the dedicated Docker network after success, assertion failure, startup failure, or timeout. A one-minute test-only `metric_expiration` deliberately remains much longer than the lease so exporter caching reproduces the old raw-query failure; production cleanup guidance remains five minutes for the default one-minute lease.
|
|
144
|
+
|
|
145
|
+
### 6.2 GitHub Actions cancellation validation
|
|
146
|
+
|
|
147
|
+
The `lease-cancellation` job in `.github/workflows/ci.yml` runs lease unit/contract tests and the focused integration on `ubuntu-latest` with a bounded timeout. It simulates cancellation by sending `SIGKILL` to a producer so the workflow can assert convergence; cancelling the validation job itself could not produce evidence about its own result. An `if: always()` step removes labeled Docker resources when GitHub still schedules cleanup, but the test must reach zero through lease expiry before that step runs.
|
|
148
|
+
|
|
149
|
+
Production workflows should likewise prefer graceful Pi and sidecar shutdown and use `if: always()` cleanup where available. Force cancellation, runner loss, or power loss can bypass both, so neither cleanup nor a shutdown callback may be the active-count correctness mechanism. GitHub-hosted runners meet the synchronized-clock expectation; self-hosted CI must keep the producer and Prometheus clocks within the supported 5-second skew.
|
|
150
|
+
|
|
126
151
|
## 7. Failure Tests
|
|
127
152
|
|
|
128
153
|
### Collector Down
|
|
@@ -228,15 +253,16 @@ Reject or sanitize dynamically generated labels.
|
|
|
228
253
|
|
|
229
254
|
## 10. Release Process
|
|
230
255
|
|
|
231
|
-
1. Update version.
|
|
232
|
-
2. Run unit tests.
|
|
233
|
-
3. Run integration
|
|
234
|
-
4. Run
|
|
235
|
-
5. Run dashboard
|
|
236
|
-
6.
|
|
237
|
-
7.
|
|
238
|
-
8.
|
|
239
|
-
9.
|
|
256
|
+
1. Update the version and `CHANGELOG.md`.
|
|
257
|
+
2. Run `npm run validate` for source/test typechecks, ESLint, formatting, script checks, unit/contract/dashboard/alert tests, package-content checks, packaged-install smoke, handler smoke, Pi lifecycle smoke, and Pi runtime smoke.
|
|
258
|
+
3. Run `npm run test:integration:collector` against the pinned Collector distribution.
|
|
259
|
+
4. Run `npm run test:integration:active-agent-lease` and require clean shutdown, `SIGTERM`, and `SIGKILL` convergence without Collector restart while the raw claim remains cached.
|
|
260
|
+
5. Run `npm run test:integration:grafana-stack` for live backends and dashboard provisioning. Record any unrelated pre-existing blocker precisely; it must not replace focused lease evidence.
|
|
261
|
+
6. Validate Compose interpolation and the Collector config with the pinned distribution when Collector/example configuration changed.
|
|
262
|
+
7. Run `npm run pack:dry-run` and confirm the lease metric source, dashboards, alerts, examples, user/operator/reference docs, and packaged `observme-docs` skill are present. Do not publish during this check.
|
|
263
|
+
8. Record sanitized date, environment versions, pass/fail status, cleanup result, and any blocker in `docs/compatibility-matrix.md` and `docs/review-validation.md`; never record credentials, raw content, private paths, commands from interactive Pi, or full high-cardinality identifiers.
|
|
264
|
+
9. Publish the package/artifact only after lease-related failures are resolved.
|
|
265
|
+
10. Tag the release.
|
|
240
266
|
|
|
241
267
|
## 11. Compatibility Matrix
|
|
242
268
|
|
|
@@ -266,6 +292,7 @@ observme_export_errors_total
|
|
|
266
292
|
observme_redaction_failures_total
|
|
267
293
|
observme_active_spans
|
|
268
294
|
observme_active_agents
|
|
295
|
+
observme_agent_lease_expires_unixtime_seconds
|
|
269
296
|
observme_workflows_started_total
|
|
270
297
|
observme_workflows_completed_total
|
|
271
298
|
observme_workflow_errors_total
|
|
@@ -313,7 +340,10 @@ When troubleshooting:
|
|
|
313
340
|
3. Run `/obs agents` when troubleshooting workflow, parent/subagent lineage, fan-out, depth, or orphan agents.
|
|
314
341
|
4. Check Collector health endpoint.
|
|
315
342
|
5. Check Collector logs.
|
|
316
|
-
6.
|
|
317
|
-
7. Query
|
|
318
|
-
8.
|
|
319
|
-
9.
|
|
343
|
+
6. For active-agent incidents, compare the canonical leased count, raw positive claims, expired claims, and direct presence of `observme_agent_lease_expires_unixtime_seconds`; then verify producer/Prometheus clock skew, `observme_instance_id` preservation, and the configured lease/export relationship.
|
|
344
|
+
7. Query `observme_export_errors_total` and inspect Export Health before deciding that a missing or expired lease means the producer stopped.
|
|
345
|
+
8. Query Loki for `event_name="export.failed"` (or equivalent normalized structured metadata).
|
|
346
|
+
9. Temporarily enable the debug exporter in the Collector.
|
|
347
|
+
10. Never enable raw content capture in production without approval.
|
|
348
|
+
|
|
349
|
+
See [`11-deployment-runbooks.md` §5](11-deployment-runbooks.md#5-common-incidents) for expired-claim and missing-lease decision trees.
|
|
@@ -88,6 +88,26 @@ Recommended ports:
|
|
|
88
88
|
9090 prometheus
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
+
### Prometheus exporter cleanup policy
|
|
92
|
+
|
|
93
|
+
The bundled Collector exposes all metrics through one Prometheus exporter with `metric_expiration: 5m`. Treat that value only as stale-series/cardinality cleanup, not as active-agent liveness. It applies to every exported gauge, counter, and histogram. The leased active-agent queries determine liveness and converge after the 60-second default lease even while a raw positive claim remains cached.
|
|
94
|
+
|
|
95
|
+
When changing `metrics.activeAgentLeaseDurationMillis`, `metrics.exportIntervalMillis`, scrape timing, or expected outage tolerance:
|
|
96
|
+
|
|
97
|
+
1. Keep `metric_expiration` longer than the active-agent lease; five minutes is the recommendation for the default 60-second lease and 15-second export interval.
|
|
98
|
+
2. Leave enough margin for ordinary export delays and scrape gaps. Shorter cleanup lowers Collector memory/cardinality but can remove every metric type during a temporary producer outage; longer cleanup retains abandoned series longer.
|
|
99
|
+
3. Preserve generated `observme.instance.id`/`service.instance.id` resource identity for lease joins, while continuing to drop workflow, session, logical-agent, trace, span, spawn, and job-run identifiers from metric labels.
|
|
100
|
+
4. Validate the configuration with the deployed Collector distribution, then use its supported reload mechanism or restart it. The bundled Compose stack requires a Collector restart.
|
|
101
|
+
5. Expect a restart to clear the exporter's in-memory cache only. Prometheus history remains stored until its normal retention or deletion policy removes it. Traces and logs are unaffected.
|
|
102
|
+
|
|
103
|
+
For the pinned local distribution, validate before restart:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
docker compose -f observability-stack/docker-compose.yml config
|
|
107
|
+
docker compose -f observability-stack/docker-compose.yml exec -T otel-collector \
|
|
108
|
+
/otelcol-contrib validate --config=/etc/otel/otel-collector.yaml
|
|
109
|
+
```
|
|
110
|
+
|
|
91
111
|
## 3. CI Agent Runbook
|
|
92
112
|
|
|
93
113
|
CI agents are short lived. Use one of:
|
|
@@ -108,13 +128,17 @@ Pi CI job -> sidecar collector -> central collector
|
|
|
108
128
|
|
|
109
129
|
Best for high-volume jobs because Pi hands off telemetry locally.
|
|
110
130
|
|
|
111
|
-
|
|
131
|
+
Preferred shutdown steps:
|
|
112
132
|
|
|
113
133
|
1. Parent Pi passes trace context, `OBSERVME_WORKFLOW_ID`, and `OBSERVME_PARENT_AGENT_ID`/`OBSERVME_ROOT_AGENT_ID` to any child Pi processes it launches.
|
|
114
|
-
2. Pi
|
|
115
|
-
3.
|
|
116
|
-
4.
|
|
117
|
-
5. CI job
|
|
134
|
+
2. Stop Pi and child producers gracefully so ObservMe can deactivate the lease, export the zero lifecycle claim, and flush within its timeout.
|
|
135
|
+
3. Drain the sidecar Collector with a timeout.
|
|
136
|
+
4. Put best-effort process, container, and network cleanup in an `if: always()` GitHub Actions step.
|
|
137
|
+
5. End the CI job.
|
|
138
|
+
|
|
139
|
+
Graceful shutdown and unconditional cleanup reduce latency and resource leakage, but forced cancellation, `SIGKILL`, runner loss, or power loss can skip both. The active count still converges from the last lease; never make a post-job step, Pi shutdown callback, or Collector restart the correctness mechanism. Test cancellation by killing a child producer from a still-running validation job, because a cancelled workflow cannot assert its own convergence.
|
|
140
|
+
|
|
141
|
+
GitHub-hosted runners satisfy the supported clock expectation. A self-hosted runner must keep its wall clock and the Prometheus clock synchronized within 5 seconds using reliable NTP or an equivalent managed time service. Monitor synchronization health and clock steps; a producer clock behind can fail closed early, while one ahead can delay expiry until the bounded future-horizon rule rejects it.
|
|
118
142
|
|
|
119
143
|
## 4. Production Configuration Checklist
|
|
120
144
|
|
|
@@ -133,6 +157,10 @@ Shutdown steps:
|
|
|
133
157
|
- [ ] Collector batch processor enabled.
|
|
134
158
|
- [ ] Loki structured metadata enabled when required by the deployed Loki version.
|
|
135
159
|
- [ ] Prometheus OTLP receiver enabled with `--web.enable-otlp-receiver` if sending directly to Prometheus.
|
|
160
|
+
- [ ] Prometheus scrape-exporter `metric_expiration` is longer than the active-agent lease and is treated only as exporter-wide cleanup.
|
|
161
|
+
- [ ] Lease-aware queries, rather than raw active claims or Collector expiration, determine active-agent liveness.
|
|
162
|
+
- [ ] Producer and Prometheus clocks are synchronized within 5 seconds; self-hosted runner time synchronization is monitored.
|
|
163
|
+
- [ ] GitHub Actions uses graceful shutdown and `if: always()` cleanup where possible without depending on either for active-count correctness.
|
|
136
164
|
- [ ] Backend retention configured.
|
|
137
165
|
- [ ] Dashboards imported.
|
|
138
166
|
- [ ] Alerts enabled.
|
|
@@ -141,6 +169,27 @@ Shutdown steps:
|
|
|
141
169
|
|
|
142
170
|
## 5. Common Incidents
|
|
143
171
|
|
|
172
|
+
### Grafana-Backed Commands Reject the Base URL
|
|
173
|
+
|
|
174
|
+
If `/obs status`, `/obs health`, or a query-backed command reports `embedded_grafana_url_credentials` or `embedded_credentials`:
|
|
175
|
+
|
|
176
|
+
1. Configure `query.grafana.url` as an absolute HTTP(S) base URL without an embedded username or password component.
|
|
177
|
+
2. Put bearer authentication in `query.grafana.token`, or configure both `query.grafana.username` and `query.grafana.password`. Prefer environment-variable references rather than secret values in YAML.
|
|
178
|
+
3. Restart Pi, then rerun `/obs status` and `/obs health`.
|
|
179
|
+
|
|
180
|
+
ObservMe rejects this URL class before default-fetch or custom-transport network I/O. Diagnostics intentionally identify only the safe failure class and setting names, never the rejected URL or credentials.
|
|
181
|
+
|
|
182
|
+
### Project Config or `.env` Is Rejected
|
|
183
|
+
|
|
184
|
+
Project-local configuration is loaded only for a trusted project and only while its lexical and canonical paths remain inside the stable canonical project root.
|
|
185
|
+
|
|
186
|
+
1. Confirm Pi marks the project trusted.
|
|
187
|
+
2. Use a normal in-root config directory and `.env` file, or symlinks whose existing targets also remain inside the same project root.
|
|
188
|
+
3. Replace out-of-root, dangling, or changing symlinks and retry the session start. Do not bypass the containment check.
|
|
189
|
+
4. Review `/obs status` for `config_source_rejected`; bootstrap failures appear as a bounded warning.
|
|
190
|
+
|
|
191
|
+
ObservMe fails closed if it cannot verify the root, target, or opened-file identity. A rejected project config or `.env` is not read, starter creation never overwrites an existing target, and diagnostics omit canonical and external path details. Other accepted configuration layers continue to apply.
|
|
192
|
+
|
|
144
193
|
### No Traces in Tempo
|
|
145
194
|
|
|
146
195
|
Check:
|
|
@@ -172,6 +221,34 @@ Check:
|
|
|
172
221
|
4. Metric names visible
|
|
173
222
|
5. Resource attributes not unexpectedly dropped
|
|
174
223
|
|
|
224
|
+
### Active Count Is Correct but Raw Claims Remain
|
|
225
|
+
|
|
226
|
+
This is expected after an ungraceful producer exit. Check:
|
|
227
|
+
|
|
228
|
+
1. The dashboard uses the leased active-agent query, not `sum(observme_active_agents)`.
|
|
229
|
+
2. The expired-claims diagnostic shows the abandoned stream.
|
|
230
|
+
3. The configured lease has elapsed and producer/Prometheus clocks are synchronized within 5 seconds.
|
|
231
|
+
4. `metric_expiration` remains longer than the lease. Do not shorten it to force correctness; the exporter will remove the raw gauge, counter, and histogram series together after the cleanup window.
|
|
232
|
+
5. Collector memory/cardinality is within budget. If cleanup timing changes, validate and reload/restart the Collector; stored Prometheus history will remain.
|
|
233
|
+
|
|
234
|
+
No Collector restart is required. Restarting clears the exporter's in-memory cache and can hide the diagnostic raw claim, but it does not improve lease convergence or delete Prometheus history.
|
|
235
|
+
|
|
236
|
+
### Live Producer Is Missing from the Leased Count
|
|
237
|
+
|
|
238
|
+
A missing, expired, malformed, or pathologically future lease fails closed. Diagnose in this order:
|
|
239
|
+
|
|
240
|
+
1. Confirm Prometheus and the Export Health dashboard are reachable. If the backend is unavailable, zero is not a reliable health result.
|
|
241
|
+
2. Compare the canonical leased total, raw positive claims, and expired claims. Query `observme_agent_lease_expires_unixtime_seconds` directly only for diagnosis; do not expose `observme_instance_id` in a public legend or variable.
|
|
242
|
+
3. If the raw claim and lease are both missing, check `metrics.enabled`, `/obs status`, `/obs health`, OTLP reachability, `observme_export_errors_total`, Collector logs, and the metrics pipeline.
|
|
243
|
+
4. If the raw claim exists but the lease is missing, confirm every expected producer runs a lease-capable ObservMe version and that the Collector preserves the same generated `observme_instance_id` label on both metrics. During a mixed-version rollout, missing leases intentionally do not count.
|
|
244
|
+
5. If the lease is expired while the producer runs, verify metric collection/export is still occurring, then inspect Export Health for drops or exporter failures. Confirm `metrics.activeAgentLeaseDurationMillis >= (2 * metrics.exportIntervalMillis) + 5000`.
|
|
245
|
+
6. If the lease is rejected as future, compare producer and Prometheus clocks. Restore reliable synchronization within 5 seconds; do not widen panel-local PromQL or remove the `time() + 305` safety bound.
|
|
246
|
+
7. After export recovers, wait for the next metric collection and Prometheus scrape. The lease renews automatically while the session remains active; neither workload activity nor Collector restart is required.
|
|
247
|
+
|
|
248
|
+
### Expired Claims Are Missing from Diagnostics
|
|
249
|
+
|
|
250
|
+
The live total can still be correct. Check whether `metric_expiration` elapsed, the Collector restarted, or the deployment uses remote write rather than the scrape exporter. Any of those can remove the current raw series while historical Prometheus samples remain. Use backend history and Export Health for incident timing; do not infer that graceful shutdown occurred merely because the expired-claim panel is empty.
|
|
251
|
+
|
|
175
252
|
### Subagents Not Linked to Parent
|
|
176
253
|
|
|
177
254
|
Check:
|
|
@@ -15,8 +15,9 @@ observme:
|
|
|
15
15
|
headers:
|
|
16
16
|
Authorization: "Bearer ${OBSERVME_OTLP_TOKEN}"
|
|
17
17
|
tls:
|
|
18
|
-
enabled: true
|
|
19
18
|
insecureSkipVerify: false
|
|
19
|
+
# The endpoint scheme selects HTTP or HTTPS. HTTPS certificate verification
|
|
20
|
+
# stays enabled unless insecureSkipVerify is explicitly acknowledged.
|
|
20
21
|
# Derived SDK URLs for OTLP/HTTP exporters:
|
|
21
22
|
# traces: https://otel-collector.example.com:4318/v1/traces
|
|
22
23
|
# metrics: https://otel-collector.example.com:4318/v1/metrics
|
|
@@ -64,6 +65,7 @@ observme:
|
|
|
64
65
|
enabled: true
|
|
65
66
|
exportIntervalMillis: 15000
|
|
66
67
|
exportTimeoutMillis: 3000
|
|
68
|
+
activeAgentLeaseDurationMillis: 60000
|
|
67
69
|
|
|
68
70
|
logs:
|
|
69
71
|
enabled: true
|
|
@@ -134,6 +136,16 @@ observme:
|
|
|
134
136
|
flushTimeoutMs: 3000
|
|
135
137
|
```
|
|
136
138
|
|
|
139
|
+
`otlp.endpoint` and every `otlp.signalEndpoints` value must be an absolute HTTP(S) URL without userinfo, unresolved placeholders, a query, or a fragment; credentials belong in `otlp.headers`. The base endpoint may contain an intentional path, to which ObservMe appends exactly one `/v1/{signal}` suffix using URL pathname semantics. Explicit signal endpoints must already end in their matching `/v1/traces`, `/v1/metrics`, or `/v1/logs` path.
|
|
140
|
+
|
|
141
|
+
`query.grafana.url` must be an absolute HTTP(S) base URL without a username or password component. Authentication belongs only in `query.grafana.token` or the complete `query.grafana.username` and `query.grafana.password` pair. Credential-bearing base URLs fail configuration validation and query/transport preflight before network I/O. Diagnostics identify the bounded `embedded_credentials` failure class without rendering the rejected URL or either credential component.
|
|
142
|
+
|
|
143
|
+
`otlp.tls.enabled` is intentionally unsupported and rejected as an unknown setting: the `http://` or `https://` endpoint scheme is the single source of truth for whether TLS is used. The retained `otlp.tls.insecureSkipVerify` option is passed to every OTLP HTTP exporter as its certificate-verification behavior.
|
|
144
|
+
|
|
145
|
+
`query.links.traceUrlTemplate` is shared by `/obs session`, `/obs trace`, and `/obs link`. Absolute HTTP(S) templates support `{traceId}`, `{{traceId}}` (with optional inner whitespace), `${traceId}`, and `%TRACE_ID%`; optional Tempo UID placeholders use the matching `{tempoDatasourceUid}`, `{{tempoDatasourceUid}}`, `${tempoDatasourceUid}`, and `%TEMPO_DATASOURCE_UID%` forms. An empty template or one containing `...` selects the structured Grafana Explore fallback built from `query.grafana.url` and `query.grafana.datasourceUids.tempo`. Unsupported placeholders and invalid URLs fail with a bounded diagnostic.
|
|
146
|
+
|
|
147
|
+
`query.maxLogs`, `query.maxTraces`, `query.maxMetricSeries`, and `query.maxAgents` accept integers from 1 through 100. Query clients enforce the same upper bound at runtime before issuing backend requests.
|
|
148
|
+
|
|
137
149
|
## 2. Environment Variables
|
|
138
150
|
|
|
139
151
|
```text
|
|
@@ -146,6 +158,7 @@ OBSERVME_OTLP_TRACES_ENDPOINT
|
|
|
146
158
|
OBSERVME_OTLP_METRICS_ENDPOINT
|
|
147
159
|
OBSERVME_OTLP_LOGS_ENDPOINT
|
|
148
160
|
OBSERVME_OTLP_TOKEN
|
|
161
|
+
OBSERVME_ACTIVE_AGENT_LEASE_DURATION_MS
|
|
149
162
|
OBSERVME_WORKFLOW_ID
|
|
150
163
|
OBSERVME_WORKFLOW_MAX_DEPTH_WARNING
|
|
151
164
|
OBSERVME_WORKFLOW_MAX_FANOUT_WARNING
|
|
@@ -184,6 +197,17 @@ OBSERVME_ALLOW_UNSAFE_CAPTURE
|
|
|
184
197
|
OBSERVME_ALLOW_INSECURE_TRANSPORT
|
|
185
198
|
```
|
|
186
199
|
|
|
200
|
+
### 2.1 Active-agent lease configuration
|
|
201
|
+
|
|
202
|
+
| Setting | Default | Supported values | Purpose |
|
|
203
|
+
| --- | --- | --- | --- |
|
|
204
|
+
| `metrics.activeAgentLeaseDurationMillis` | `60000` | Integer `10000`–`300000`, and at least `(2 * metrics.exportIntervalMillis) + 5000` | Validity window renewed on each metric collection while the session is active. |
|
|
205
|
+
| `OBSERVME_ACTIVE_AGENT_LEASE_DURATION_MS` | unset | Same as the YAML field | Environment override through the normal trusted `.env` / system environment precedence. |
|
|
206
|
+
|
|
207
|
+
The value controls failure-convergence latency, not a background timer. A clean shutdown deactivates the lease before final flush and reaches zero after normal export/scrape propagation. An ungraceful exit reaches zero within the configured lease plus up to 5 seconds of supported clock skew and one Prometheus scrape/evaluation interval. Missing or invalid leases fail closed. Keep producer and Prometheus clocks synchronized within 5 seconds; GitHub-hosted runners meet this requirement, while self-hosted runners need reliable time synchronization.
|
|
208
|
+
|
|
209
|
+
Do not tune this field by shortening Collector `metric_expiration`. The recommended five-minute exporter cleanup remains longer than the default lease and applies to all gauges, counters, and histograms. Changing Collector configuration may require reload or restart, but restart is not required for active-agent correctness.
|
|
210
|
+
|
|
187
211
|
## 3. Workflow and Agent Lineage Configuration
|
|
188
212
|
|
|
189
213
|
The `workflow:` and `agent:` config blocks control generated workflow identity, generated agent identity, and parent/child propagation. `pi.workflow.id`, `pi.agent.id`, `pi.agent.parent_id`, and related values are high-cardinality identifiers for traces/logs only; they must not be metric labels by default.
|
|
@@ -198,7 +222,8 @@ Rules:
|
|
|
198
222
|
- Continue a valid W3C parent context explicitly on the child `pi.session` span. If trusted lineage has no usable continuation, start a new trace and add a validated parent span link when metadata exists, otherwise emit the documented propagation-failure log/counter fallback.
|
|
199
223
|
- When `propagateTraceContext` is true, propagate W3C `traceparent`/`tracestate` to child processes launched by ObservMe-aware subagent wrappers.
|
|
200
224
|
- When `workflow.enabled` is true, propagate `OBSERVME_WORKFLOW_ID` to child processes and report depth/fan-out/orphan metrics.
|
|
201
|
-
- `writeCorrelationEntry`
|
|
225
|
+
- `writeCorrelationEntry` defaults to `false`. When enabled, successful startup appends at most one versioned `observme.correlation` `custom` entry to the active branch. Reload/resume/fork recovery scans only `ctx.sessionManager.getBranch()`, accepts the latest valid bounded lineage entry, ignores corrupt or abandoned-branch data, and does not duplicate an unchanged entry. ObservMe never uses `custom_message`, so this state cannot enter LLM context.
|
|
226
|
+
- Historical telemetry is never replayed automatically. Use the explicit, confirmed `/obs backfill` command. The removed `replayOnStart` YAML field is rejected as unknown, and `OBSERVME_REPLAY_ON_START` is no longer recognized; neither can emit a synthetic duplicate startup record.
|
|
202
227
|
|
|
203
228
|
## 4. Config Precedence
|
|
204
229
|
|
|
@@ -211,6 +236,17 @@ Rules:
|
|
|
211
236
|
|
|
212
237
|
Copy `.env.example` to `.env` for project-local extension variables, or export the same `OBSERVME_*` names in the shell before starting Pi. System environment variables override `.env` values, and `.env` must never be committed. If redacted content capture is enabled, set `OBSERVME_HASH_SALT` in the shell or trusted project `.env`; missing salts make capture fail closed.
|
|
213
238
|
|
|
239
|
+
### 4.1 Project-Local Path and Symlink Policy
|
|
240
|
+
|
|
241
|
+
Project config, project `.env`, and starter-config creation use the same fail-closed filesystem policy:
|
|
242
|
+
|
|
243
|
+
- Pi must mark the project trusted before ObservMe reads or creates a project-local file.
|
|
244
|
+
- The lexical path and resolved canonical target must both remain inside one stable canonical project root.
|
|
245
|
+
- Existing file or directory symlinks are supported when their targets remain inside that root. Out-of-root, dangling, or unverifiable symlinks are rejected.
|
|
246
|
+
- Reads and creates use opened file handles whose file identity, root identity, and canonical containment are verified before bytes are consumed or written. Concurrent replacement of a file, ancestor, or project root therefore rejects the operation instead of following the substituted target.
|
|
247
|
+
- Normal missing in-root paths remain supported. Starter creation is exclusive and idempotent, never overwrites an existing file, and removes an unverified empty target if post-open validation fails.
|
|
248
|
+
- Rejected project sources use the bounded `config_source_rejected` classification. Warnings and status diagnostics do not include canonical targets, external paths, file contents, or environment values; the rejected layer is skipped and other accepted layers continue to apply.
|
|
249
|
+
|
|
214
250
|
Automatic project starter file:
|
|
215
251
|
|
|
216
252
|
- On `session_start`, the extension creates `<cwd>/<CONFIG_DIR_NAME>/observme.yaml` (`<cwd>/.pi/observme.yaml` in the standard distribution) when the project is trusted and the file is missing.
|
|
@@ -243,6 +279,9 @@ agent:
|
|
|
243
279
|
writeCorrelationEntry: false
|
|
244
280
|
workflow:
|
|
245
281
|
enabled: true
|
|
282
|
+
metrics:
|
|
283
|
+
exportIntervalMillis: 15000
|
|
284
|
+
activeAgentLeaseDurationMillis: 60000
|
|
246
285
|
```
|
|
247
286
|
|
|
248
287
|
## 6. Development Defaults
|
|
@@ -291,7 +330,7 @@ Rules:
|
|
|
291
330
|
- When the token is blank or an unresolved placeholder, a resolved `query.grafana.username` and `query.grafana.password` are sent as Basic auth for local development.
|
|
292
331
|
- Query-backed commands and `/obs health` must fail fast before Grafana calls when Grafana auth is unresolved/missing/incomplete, `query.grafana.url` is invalid, or a required datasource UID is blank.
|
|
293
332
|
- `/obs health` must report Grafana `401`/`403` responses as authentication failures and must not print token or password values.
|
|
294
|
-
- `tls.insecureSkipVerify=true` is only for local self-signed certificates; production should trust the CA instead.
|
|
333
|
+
- `query.grafana.tls.insecureSkipVerify=true` is only for local self-signed certificates; production requires `privacy.allowInsecureTransport=true` as an explicit acknowledgement and should trust the CA instead.
|
|
295
334
|
- `transport.preferIPv4=true` uses Node's local HTTP(S) transport with IPv4 DNS lookup for Grafana calls.
|
|
296
335
|
- Provisioned datasource UIDs are `tempo`, `loki`, and `prometheus`; Loki selectors use normalized labels such as `service_name`, `pi_session_id`, `event_name`, and `event_category` for ObservMe data.
|
|
297
336
|
|
|
@@ -319,10 +358,14 @@ ObservMe must display a warning when unsafe capture is active. Redacted capture
|
|
|
319
358
|
Reject config when:
|
|
320
359
|
|
|
321
360
|
- `allowUnsafeCapture=false` and `redactionEnabled=false` while any content capture is true.
|
|
322
|
-
-
|
|
361
|
+
- A production OTLP or Grafana endpoint uses `http://` and `privacy.allowInsecureTransport` is not true.
|
|
362
|
+
- `query.grafana.url` contains an embedded username or password instead of using the dedicated token or username/password settings.
|
|
363
|
+
- Production sets `otlp.tls.insecureSkipVerify=true` or `query.grafana.tls.insecureSkipVerify=true` and `privacy.allowInsecureTransport` is not true.
|
|
323
364
|
- `otlp.protocol=http/protobuf` but a signal-specific exporter URL omits the required `/v1/traces`, `/v1/metrics`, or `/v1/logs` path.
|
|
324
|
-
-
|
|
365
|
+
- `metrics.activeAgentLeaseDurationMillis` is fractional, non-numeric, below `10000`, above `300000`, or less than `(2 * metrics.exportIntervalMillis) + 5000`.
|
|
366
|
+
- Metric labels include high-cardinality fields such as workflow IDs, session IDs, agent IDs, parent/child agent IDs, trace IDs, span IDs, entry IDs, spawn IDs, or spawn tool-call IDs. The generated `observme.instance.id` / `service.instance.id` remains a resource identity used by the Collector for the `observme_instance_id` lease join; it must not be configured as an execution-derived label.
|
|
325
367
|
- Project-local config is read while `ctx.isProjectTrusted()` is false.
|
|
368
|
+
- A project config, project `.env`, or starter-config path escapes the canonical project root, changes identity during I/O, or cannot be verified safely.
|
|
326
369
|
- Propagated workflow or agent lineage values are malformed, too long, or contain unsafe characters.
|
|
327
370
|
- Queue sizes exceed configured memory guardrails.
|
|
328
371
|
|
|
@@ -55,6 +55,7 @@ Use this checklist when a review, release candidate, or local operator needs cov
|
|
|
55
55
|
| `npm run smoke:pi-runtime` | Yes when the `pi` CLI is installed in the test image | A working local `pi` executable, dependencies installed, and permission to spawn a local child process. | No credentials. It deletes inherited `OBSERVME_*` values and uses a deterministic loopback backend. | Creates a temporary project and extension files under the OS temp directory, then removes them; local loopback server only. | Real Pi RPC extension load, `/obs` discovery/routing, reload/new-session replacement, and credential-free event-shape smoke coverage. |
|
|
56
56
|
| `npm run smoke:packaged` | Usually release/local only | `npm` available and package dependencies resolvable for a temporary install. | May need npm registry/cache access to install package dependencies; no project credentials. | Runs `npm pack`, creates a temporary project under the OS temp directory, installs the tarball with `--ignore-scripts --no-audit --no-fund --package-lock=false`, and removes the temp directory. | Packaged install layout plus declared Pi extension and skill resources in the installed package. |
|
|
57
57
|
| `npm run test:integration:collector` | No | Docker daemon available; Collector image `OBSERVME_COLLECTOR_IMAGE` or `otel/opentelemetry-collector-contrib:0.104.0` pullable or cached. | Docker image pull may require network; no Grafana/model credentials. | Starts a temporary Collector container with loopback-published ports and stops it in test cleanup. | OTLP export to Collector debug pipeline for representative traces, metrics, and logs. |
|
|
58
|
+
| `npm run test:integration:active-agent-lease` | No | Docker daemon available; pinned Collector Contrib and Prometheus images pullable or cached; producer and Prometheus clocks within 5 seconds. | Docker image pull may require network; no project, Grafana, or model credentials. | Creates labeled Collector/Prometheus containers and a dedicated network plus local child producers; bounded `finally` cleanup removes all resources. | Clean shutdown, `SIGTERM`, and cancellation-oriented `SIGKILL`; cached raw claim remains while lease-aware activity reaches zero without Collector restart. |
|
|
58
59
|
| `npm run test:integration:grafana-stack` | No | Docker Compose available; `observability-stack/docker-compose.yml` and test overlay available; required Grafana/Tempo/Loki/Prometheus images pullable or cached. | Docker image pull may require network; no external Grafana credentials. Test-created local Grafana admin secret is synthetic. | Creates isolated Docker Compose project/networks/containers. May create `observability-stack/secrets/grafana_admin_password` when missing and removes the test-created file during cleanup; also creates temporary command-project files under the OS temp directory. If interrupted, run `docker compose` with the printed project name or remove stale `observme-grafana-it-*` resources. | Live local stack ingestion, datasource queries, `/obs` query commands, and dashboard provisioning imports. |
|
|
59
60
|
| `npm run validate:grafana-obs` | No | Running Pi session with ObservMe loaded, reachable Collector/Grafana stack, and recent telemetry. See `docs/validation-flow.md`. | Requires Grafana read credentials from environment variables (`OBSERVME_GRAFANA_TOKEN` or username/password), datasource UIDs, and `OBSERVME_VALIDATION_SESSION_ID`; may access the configured Grafana URL. | Read-only against the configured stack; no file writes expected. Keep terminal output sanitized and omit secrets. | Operator-facing validation that Grafana has ObservMe data and representative `/obs` commands work against the same stack. |
|
|
60
61
|
|
|
@@ -76,6 +77,22 @@ This record was produced for the final-pass task "Run and record bounded live Pi
|
|
|
76
77
|
|
|
77
78
|
Post-run cleanup check: `docker ps --filter name=observme-grafana-it --format '{{.Names}}'` and `docker network ls --filter name=observme-grafana-it --format '{{.Name}}'` returned no resources.
|
|
78
79
|
|
|
80
|
+
## Active-agent lease release validation — 2026-07-14
|
|
81
|
+
|
|
82
|
+
This sanitized record covers the production active-agent lease release candidate on local Node.js v26.0.0, npm 11.12.1, Docker 29.5.2, and Docker Compose 5.1.4. The checkout contains the lease implementation and documentation changes. No project, Grafana, model, or registry credentials were required or printed.
|
|
83
|
+
|
|
84
|
+
| Command | Result | Evidence and notes |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| `npm run validate` | Pass | Source/test typechecks, ESLint, formatting, script checks, 493 unit/contract tests, package-content checks, packaged-install smoke, handler smoke, Pi lifecycle smoke, and Pi runtime smoke passed. |
|
|
87
|
+
| `npm run test:integration:collector` | Pass | The pinned Collector Contrib 0.104.0 debug pipeline received representative traces, metrics, and logs without default content capture. |
|
|
88
|
+
| `npm run test:integration:active-agent-lease` | Pass | Clean shutdown, `SIGTERM`, and cancellation-oriented `SIGKILL` passed against Collector Contrib 0.104.0 and Prometheus 2.53.1. The raw claim remained cached while lease-aware activity reached zero with the same Collector instance and no restart. |
|
|
89
|
+
| `npm run test:integration:grafana-stack` | Fail/unrelated pre-existing broad-stack blocker | The current run timed out when the Prometheus total-token query returned an empty vector. This token-ingestion/query path is unrelated to active-agent lease arithmetic, PromQL, or abrupt-termination convergence and does not invalidate the focused passing lease evidence. The earlier 2026-07-09 broad-stack run was already blocked later in its Tempo content assertion. |
|
|
90
|
+
| `docker compose -f observability-stack/docker-compose.yml config --quiet` | Pass | Compose interpolation validated without rendering secret values. |
|
|
91
|
+
| Pinned Collector Contrib 0.104.0 `validate --config=/etc/otel/otel-collector.yaml` | Pass | The shipped `observability-stack/config/otel/otel-collector.yaml` parsed successfully with the deployed distribution. |
|
|
92
|
+
| `npm run pack:dry-run` | Pass | The 124-file package contained the lease source/metric convention, dashboards, alerts, examples, target user/operator/reference docs, and packaged `observme-docs` skill. |
|
|
93
|
+
|
|
94
|
+
Post-run cleanup check found no containers or networks labeled for the active-agent lease integration and no `observme-grafana-it-*` containers or networks. Release remains blocked on the unrelated broad Grafana-stack validation unless the release owner accepts the explicitly allowed pre-existing blocker; all lease-specific release criteria passed.
|
|
95
|
+
|
|
79
96
|
## Review-closure evidence categories
|
|
80
97
|
|
|
81
98
|
- **Read-only/check-only** — commands that inspect, type-check, lint, audit, run tests, dry-run packaging, or smoke local deterministic fixtures without publishing or writing tracked files.
|
package/examples/README.md
CHANGED
|
@@ -11,6 +11,7 @@ The npm package ships configuration examples and an extension-integration exampl
|
|
|
11
11
|
- Local self-signed TLS and IPv4 preference are enabled for that profile.
|
|
12
12
|
- Prompt, response, thinking, tool, Bash, and path capture remain disabled.
|
|
13
13
|
- Redaction remains enabled and unsafe capture remains disabled.
|
|
14
|
+
- Metrics export every 15 seconds and renew a 60-second active-agent lease; keep producer and Prometheus clocks synchronized within 5 seconds.
|
|
14
15
|
|
|
15
16
|
To use it in a trusted project:
|
|
16
17
|
|
|
@@ -27,13 +28,17 @@ Read [`../docs/configuration.md`](../docs/configuration.md) for the quick guide
|
|
|
27
28
|
|
|
28
29
|
- traces are exported to Tempo;
|
|
29
30
|
- logs are exported to Loki;
|
|
30
|
-
- metrics are
|
|
31
|
+
- metrics are exposed on a Prometheus scrape endpoint;
|
|
32
|
+
- the five-minute `metric_expiration` applies to all exported metric types only as stale-series/cardinality cleanup, not active-agent liveness;
|
|
33
|
+
- lease-aware PromQL joins the positive lifecycle claim and lease on generated `observme_instance_id`; raw `observme_active_agents` sums are diagnostics, not production live totals;
|
|
31
34
|
- high-cardinality workflow, agent, session, and spawn attributes are removed from metrics;
|
|
32
35
|
- accidental content attributes are removed from logs as defense in depth.
|
|
33
36
|
|
|
34
37
|
The example uses Collector components commonly provided by the Collector Contrib distribution. Verify that your deployed distribution includes every receiver, processor, and exporter, then replace backend endpoints and security settings for your environment.
|
|
35
38
|
|
|
36
|
-
Read [`../docs/reference/05-otel-pipeline-and-collector.md`](../docs/reference/05-otel-pipeline-and-collector.md) for pipeline design and [`../docs/reference/11-deployment-runbooks.md`](../docs/reference/11-deployment-runbooks.md) for deployment and incident checks.
|
|
39
|
+
Read [`../docs/reference/05-otel-pipeline-and-collector.md`](../docs/reference/05-otel-pipeline-and-collector.md) for pipeline design, [`../docs/reference/09-dashboards-alerts-slos.md`](../docs/reference/09-dashboards-alerts-slos.md#131-canonical-active-agent-promql) for canonical queries and raw-query migration, and [`../docs/reference/11-deployment-runbooks.md`](../docs/reference/11-deployment-runbooks.md) for deployment and incident checks.
|
|
40
|
+
|
|
41
|
+
For GitHub Actions, prefer graceful Pi/sidecar shutdown and an `if: always()` cleanup step, but do not depend on either after force cancellation. Lease expiry provides correctness without a Collector restart. GitHub-hosted runner clocks meet the supported expectation; self-hosted runners must use reliable time synchronization.
|
|
37
42
|
|
|
38
43
|
## `integrations/subagent-runner.ts`
|
|
39
44
|
|
package/examples/collector.yaml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Production-oriented Collector reference for Tempo, Loki, and
|
|
1
|
+
# Production-oriented Collector reference for Tempo, Loki, and Prometheus.
|
|
2
2
|
# Verify that your Collector distribution contains every configured component,
|
|
3
3
|
# replace backend endpoints/security for your deployment, and never add raw
|
|
4
4
|
# content or high-cardinality execution identifiers to metric labels.
|
|
@@ -97,14 +97,14 @@ exporters:
|
|
|
97
97
|
retry_on_failure:
|
|
98
98
|
enabled: true
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
endpoint:
|
|
100
|
+
prometheus:
|
|
101
|
+
endpoint: 0.0.0.0:8889
|
|
102
|
+
# Exporter-wide stale-series/cardinality cleanup for gauges, counters, and
|
|
103
|
+
# histograms. Five minutes exceeds ObservMe's default one-minute active-agent
|
|
104
|
+
# lease; lease-aware PromQL, not expiration, determines liveness.
|
|
105
|
+
metric_expiration: 5m
|
|
102
106
|
resource_to_telemetry_conversion:
|
|
103
107
|
enabled: true
|
|
104
|
-
sending_queue:
|
|
105
|
-
enabled: true
|
|
106
|
-
retry_on_failure:
|
|
107
|
-
enabled: true
|
|
108
108
|
|
|
109
109
|
debug:
|
|
110
110
|
verbosity: basic
|
|
@@ -120,7 +120,7 @@ service:
|
|
|
120
120
|
metrics:
|
|
121
121
|
receivers: [otlp]
|
|
122
122
|
processors: [memory_limiter, resource/observme, resource/drop_high_cardinality_metric_attrs, batch]
|
|
123
|
-
exporters: [
|
|
123
|
+
exporters: [prometheus]
|
|
124
124
|
|
|
125
125
|
logs:
|
|
126
126
|
receivers: [otlp]
|