@bli-cockpit/telemetry-core 0.1.26 → 0.1.28

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.
@@ -56,6 +56,8 @@ export declare const CollectorHeartbeatSchema: z.ZodObject<{
56
56
  last_sync_reason: z.ZodOptional<z.ZodString>;
57
57
  sessions_observed: z.ZodOptional<z.ZodNumber>;
58
58
  sessions_outside_root: z.ZodOptional<z.ZodNumber>;
59
+ sessions_new_this_tick: z.ZodOptional<z.ZodNumber>;
60
+ sessions_pending_upload: z.ZodOptional<z.ZodNumber>;
59
61
  }, z.core.$strict>;
60
62
  export type CollectorHeartbeat = z.infer<typeof CollectorHeartbeatSchema>;
61
63
  /**
@@ -89,6 +89,29 @@ export const CollectorHeartbeatSchema = z
89
89
  .nonnegative()
90
90
  .max(1_000_000)
91
91
  .optional(),
92
+ /**
93
+ * BLI-3645. Two honest counters beside the raw scan count above, both
94
+ * optional so a collector too old to compute them keeps posting:
95
+ *
96
+ * - `sessions_new_this_tick` — sessions first seen since this source's
97
+ * cursor as it stood before this tick, a FLOW, not the re-scanned
98
+ * STOCK `sessions_observed` is.
99
+ * - `sessions_pending_upload` — sessions inside an approved root with
100
+ * no durable pointer yet, i.e. the "only copy" set. A FLOOR at the
101
+ * moment this tick observed it, same as every other counter here.
102
+ */
103
+ sessions_new_this_tick: z
104
+ .number()
105
+ .int()
106
+ .nonnegative()
107
+ .max(1_000_000)
108
+ .optional(),
109
+ sessions_pending_upload: z
110
+ .number()
111
+ .int()
112
+ .nonnegative()
113
+ .max(1_000_000)
114
+ .optional(),
92
115
  })
93
116
  .strict();
94
117
  /**
@@ -0,0 +1,88 @@
1
+ /**
2
+ * "Is this pack the server has no record of actually durable, or did it just
3
+ * fall out of this laptop's own memory?" — the wire contract for asking.
4
+ *
5
+ * BLI-3619. The local upload ledger (`cursors/raw-evidence.json` `objects`) is
6
+ * capped at 5,000 rows, so a pack staged before the ledger's own memory begins
7
+ * reads `unknown` locally — not because it was never delivered, but because the
8
+ * ledger that would say so has forgotten. `unknown` is never deleted, but on a
9
+ * machine running for months it grows without bound. This is the one door that
10
+ * resolves it: ask the dashboard's own upload ledger
11
+ * (`ambient_raw_evidence_upload_ledger`), by content hash, whether THIS
12
+ * device's copy of those bytes ever landed.
13
+ *
14
+ * Deliberately keyed on `content_hash_sha256` alone, never `pack_id` — a pack
15
+ * id is a local directory name the server has never seen and has no column
16
+ * for. The collector may ask about the same hash on behalf of several packs
17
+ * (duplicate content is not impossible); the answer applies to the hash, and
18
+ * the collector applies it to every local object that hash matches.
19
+ *
20
+ * Three verdicts, not two, because collapsing them would erase the difference
21
+ * the doctor row needs to report honestly:
22
+ * committed a ledger row for this device, this hash, is
23
+ * `status = "committed"`. Durable. Prunable under the
24
+ * normal retention rule from here on.
25
+ * not_committed a ledger row exists for this device and this hash, but
26
+ * it never reached `committed` (pending/aborted/failed).
27
+ * The server started a transaction and it did not finish.
28
+ * unknown_to_server no ledger row at all for this device, this hash. The
29
+ * server has never heard of these bytes.
30
+ * Both `not_committed` and `unknown_to_server` become the collector's ordinary
31
+ * `uncommitted` state — never deleted — the label only changes what a person is
32
+ * told about why.
33
+ */
34
+ import { z } from "zod";
35
+ export declare const EVIDENCE_RECONCILE_SCHEMA_VERSION = "evidence-reconcile.v1";
36
+ /** One request may ask about at most this many hashes. */
37
+ export declare const EVIDENCE_RECONCILE_MAX_BATCH = 500;
38
+ export declare const EvidenceReconcileRequestItemSchema: z.ZodObject<{
39
+ content_hash_sha256: z.ZodString;
40
+ }, z.core.$strict>;
41
+ export type EvidenceReconcileRequestItem = z.infer<typeof EvidenceReconcileRequestItemSchema>;
42
+ export declare const EvidenceReconcileRequestSchema: z.ZodObject<{
43
+ schema_version: z.ZodLiteral<"evidence-reconcile.v1">;
44
+ items: z.ZodArray<z.ZodObject<{
45
+ content_hash_sha256: z.ZodString;
46
+ }, z.core.$strict>>;
47
+ }, z.core.$strict>;
48
+ export type EvidenceReconcileRequest = z.infer<typeof EvidenceReconcileRequestSchema>;
49
+ export declare const EvidenceReconcileVerdictSchema: z.ZodEnum<{
50
+ committed: "committed";
51
+ not_committed: "not_committed";
52
+ unknown_to_server: "unknown_to_server";
53
+ }>;
54
+ export type EvidenceReconcileVerdict = z.infer<typeof EvidenceReconcileVerdictSchema>;
55
+ export declare const EvidenceReconcileResultSchema: z.ZodObject<{
56
+ content_hash_sha256: z.ZodString;
57
+ verdict: z.ZodEnum<{
58
+ committed: "committed";
59
+ not_committed: "not_committed";
60
+ unknown_to_server: "unknown_to_server";
61
+ }>;
62
+ committed_at: z.ZodNullable<z.ZodString>;
63
+ }, z.core.$strict>;
64
+ export type EvidenceReconcileResult = z.infer<typeof EvidenceReconcileResultSchema>;
65
+ export declare const EvidenceReconcileCountsSchema: z.ZodObject<{
66
+ committed: z.ZodNumber;
67
+ not_committed: z.ZodNumber;
68
+ unknown_to_server: z.ZodNumber;
69
+ }, z.core.$strict>;
70
+ export type EvidenceReconcileCounts = z.infer<typeof EvidenceReconcileCountsSchema>;
71
+ export declare const EvidenceReconcileResponseSchema: z.ZodObject<{
72
+ schema_version: z.ZodLiteral<"evidence-reconcile.v1">;
73
+ results: z.ZodArray<z.ZodObject<{
74
+ content_hash_sha256: z.ZodString;
75
+ verdict: z.ZodEnum<{
76
+ committed: "committed";
77
+ not_committed: "not_committed";
78
+ unknown_to_server: "unknown_to_server";
79
+ }>;
80
+ committed_at: z.ZodNullable<z.ZodString>;
81
+ }, z.core.$strict>>;
82
+ counts: z.ZodObject<{
83
+ committed: z.ZodNumber;
84
+ not_committed: z.ZodNumber;
85
+ unknown_to_server: z.ZodNumber;
86
+ }, z.core.$strict>;
87
+ }, z.core.$strict>;
88
+ export type EvidenceReconcileResponse = z.infer<typeof EvidenceReconcileResponseSchema>;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * "Is this pack the server has no record of actually durable, or did it just
3
+ * fall out of this laptop's own memory?" — the wire contract for asking.
4
+ *
5
+ * BLI-3619. The local upload ledger (`cursors/raw-evidence.json` `objects`) is
6
+ * capped at 5,000 rows, so a pack staged before the ledger's own memory begins
7
+ * reads `unknown` locally — not because it was never delivered, but because the
8
+ * ledger that would say so has forgotten. `unknown` is never deleted, but on a
9
+ * machine running for months it grows without bound. This is the one door that
10
+ * resolves it: ask the dashboard's own upload ledger
11
+ * (`ambient_raw_evidence_upload_ledger`), by content hash, whether THIS
12
+ * device's copy of those bytes ever landed.
13
+ *
14
+ * Deliberately keyed on `content_hash_sha256` alone, never `pack_id` — a pack
15
+ * id is a local directory name the server has never seen and has no column
16
+ * for. The collector may ask about the same hash on behalf of several packs
17
+ * (duplicate content is not impossible); the answer applies to the hash, and
18
+ * the collector applies it to every local object that hash matches.
19
+ *
20
+ * Three verdicts, not two, because collapsing them would erase the difference
21
+ * the doctor row needs to report honestly:
22
+ * committed a ledger row for this device, this hash, is
23
+ * `status = "committed"`. Durable. Prunable under the
24
+ * normal retention rule from here on.
25
+ * not_committed a ledger row exists for this device and this hash, but
26
+ * it never reached `committed` (pending/aborted/failed).
27
+ * The server started a transaction and it did not finish.
28
+ * unknown_to_server no ledger row at all for this device, this hash. The
29
+ * server has never heard of these bytes.
30
+ * Both `not_committed` and `unknown_to_server` become the collector's ordinary
31
+ * `uncommitted` state — never deleted — the label only changes what a person is
32
+ * told about why.
33
+ */
34
+ import { z } from "zod";
35
+ import { IsoDateTimeSchema, Sha256Schema } from "./common.js";
36
+ export const EVIDENCE_RECONCILE_SCHEMA_VERSION = "evidence-reconcile.v1";
37
+ /** One request may ask about at most this many hashes. */
38
+ export const EVIDENCE_RECONCILE_MAX_BATCH = 500;
39
+ export const EvidenceReconcileRequestItemSchema = z
40
+ .object({
41
+ content_hash_sha256: Sha256Schema,
42
+ })
43
+ .strict();
44
+ export const EvidenceReconcileRequestSchema = z
45
+ .object({
46
+ schema_version: z.literal(EVIDENCE_RECONCILE_SCHEMA_VERSION),
47
+ items: z
48
+ .array(EvidenceReconcileRequestItemSchema)
49
+ .min(1)
50
+ .max(EVIDENCE_RECONCILE_MAX_BATCH),
51
+ })
52
+ .strict();
53
+ export const EvidenceReconcileVerdictSchema = z.enum([
54
+ "committed",
55
+ "not_committed",
56
+ "unknown_to_server",
57
+ ]);
58
+ export const EvidenceReconcileResultSchema = z
59
+ .object({
60
+ content_hash_sha256: Sha256Schema,
61
+ verdict: EvidenceReconcileVerdictSchema,
62
+ /** Present only when `verdict === "committed"`. */
63
+ committed_at: IsoDateTimeSchema.nullable(),
64
+ })
65
+ .strict();
66
+ export const EvidenceReconcileCountsSchema = z
67
+ .object({
68
+ committed: z.number().int().nonnegative(),
69
+ not_committed: z.number().int().nonnegative(),
70
+ unknown_to_server: z.number().int().nonnegative(),
71
+ })
72
+ .strict();
73
+ export const EvidenceReconcileResponseSchema = z
74
+ .object({
75
+ schema_version: z.literal(EVIDENCE_RECONCILE_SCHEMA_VERSION),
76
+ results: z.array(EvidenceReconcileResultSchema),
77
+ counts: EvidenceReconcileCountsSchema,
78
+ })
79
+ .strict();
@@ -354,8 +354,8 @@ export type RawEvidenceUploadCommitRequest = z.infer<typeof RawEvidenceUploadCom
354
354
  export declare const RawEvidenceUploadCommitResponseSchema: z.ZodObject<{
355
355
  ok: z.ZodLiteral<true>;
356
356
  status: z.ZodEnum<{
357
- already_committed: "already_committed";
358
357
  committed: "committed";
358
+ already_committed: "already_committed";
359
359
  }>;
360
360
  object_key: z.ZodString;
361
361
  content_hash_sha256: z.ZodString;
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export * from "./common.js";
4
4
  export * from "./decision-event.js";
5
5
  export * from "./decision-event-id.js";
6
6
  export * from "./evidence-completeness.js";
7
+ export * from "./evidence-reconcile.js";
7
8
  export * from "./evidence-upload.js";
8
9
  export * from "./ingest-dto.js";
9
10
  export * from "./local-config.js";
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ export * from "./common.js";
4
4
  export * from "./decision-event.js";
5
5
  export * from "./decision-event-id.js";
6
6
  export * from "./evidence-completeness.js";
7
+ export * from "./evidence-reconcile.js";
7
8
  export * from "./evidence-upload.js";
8
9
  export * from "./ingest-dto.js";
9
10
  export * from "./local-config.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bli-cockpit/telemetry-core",
3
- "version": "0.1.26",
3
+ "version": "0.1.28",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",