@bli-cockpit/telemetry-core 0.1.29 → 0.1.30

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.
@@ -401,6 +401,8 @@ export declare const TelemetryIngestEnvelopeSchema: z.ZodObject<{
401
401
  started_at: z.ZodString;
402
402
  updated_at: z.ZodOptional<z.ZodString>;
403
403
  active_ticket_id: z.ZodOptional<z.ZodString>;
404
+ tower_issue_id: z.ZodOptional<z.ZodString>;
405
+ linear_ticket_id: z.ZodOptional<z.ZodString>;
404
406
  ticket_binding_candidates: z.ZodDefault<z.ZodArray<z.ZodObject<{
405
407
  ticket_id: z.ZodString;
406
408
  binding_source: z.ZodEnum<{
@@ -1 +1,44 @@
1
+ /**
2
+ * WHICH TRACKER MINTED THIS ID (BLI-3779).
3
+ *
4
+ * Tower runs its own issue tracker beside Linear during the dual-run, and both
5
+ * spell an identifier the same way: a team key, a hyphen, a number. Two facts
6
+ * tell them apart, and neither is a guess:
7
+ *
8
+ * - **The number.** Tower's tracker mints from `BLI-10001` up;
9
+ * Linear's BLI team is in the 3,000s. An id at or above
10
+ * `TOWER_NATIVE_ISSUE_NUMBER_FLOOR` is one only Tower could have issued.
11
+ * The dashboard's `lib/jarvis/chat-v2/issue-word-boundary.ts` (BLI-3783)
12
+ * re-exports this constant rather than keeping a second copy of it.
13
+ * - **The title.** A Tower-native row that mirrors a Linear ticket ends its
14
+ * title with `[BLI-3779]` — Edward's dogfooding convention, 2026-09-05 —
15
+ * so the Linear id a Tower row stands for is READ, never inferred.
16
+ *
17
+ * Exact after upper-casing, never fuzzy: the `person-identity.ts` discipline,
18
+ * for the same reason. A wrong match binds a session's work to somebody
19
+ * else's ticket.
20
+ */
21
+ /**
22
+ * The first identifier Tower's own tracker mints. Linear's BLI team is in the
23
+ * 3,000s as of 2026-09-05 and would need six thousand more tickets to reach
24
+ * it; if it ever does, this constant moves and `work_issues.source` becomes
25
+ * the only honest discriminator.
26
+ */
27
+ export declare const TOWER_NATIVE_ISSUE_NUMBER_FLOOR = 10000;
1
28
  export declare function parseTicketIdFromText(value: string): string | null;
29
+ /** Is this the shape either tracker uses for an identifier? */
30
+ export declare function looksLikeIssueIdentifier(value: string): boolean;
31
+ /** The one spelling of an identifier: trimmed and upper-cased, or null. */
32
+ export declare function normalizeIssueIdentifier(value: string): string | null;
33
+ /**
34
+ * Is this an id only TOWER's tracker could have minted? A fact about the
35
+ * number, not a claim about any row: `BLI-10042` cannot be in Linear whether
36
+ * or not it is in Tower.
37
+ */
38
+ export declare function isTowerNativeIssueId(value: string): boolean;
39
+ /**
40
+ * The Linear id a Tower-native title mirrors: the LAST `[BLI-3779]` in the
41
+ * title, because a title may quote another ticket in its prose and the
42
+ * convention puts the mirrored id at the end.
43
+ */
44
+ export declare function mirroredTicketIdInTitle(title: string): string | null;
package/dist/ticket-id.js CHANGED
@@ -1,4 +1,61 @@
1
+ /**
2
+ * WHICH TRACKER MINTED THIS ID (BLI-3779).
3
+ *
4
+ * Tower runs its own issue tracker beside Linear during the dual-run, and both
5
+ * spell an identifier the same way: a team key, a hyphen, a number. Two facts
6
+ * tell them apart, and neither is a guess:
7
+ *
8
+ * - **The number.** Tower's tracker mints from `BLI-10001` up;
9
+ * Linear's BLI team is in the 3,000s. An id at or above
10
+ * `TOWER_NATIVE_ISSUE_NUMBER_FLOOR` is one only Tower could have issued.
11
+ * The dashboard's `lib/jarvis/chat-v2/issue-word-boundary.ts` (BLI-3783)
12
+ * re-exports this constant rather than keeping a second copy of it.
13
+ * - **The title.** A Tower-native row that mirrors a Linear ticket ends its
14
+ * title with `[BLI-3779]` — Edward's dogfooding convention, 2026-09-05 —
15
+ * so the Linear id a Tower row stands for is READ, never inferred.
16
+ *
17
+ * Exact after upper-casing, never fuzzy: the `person-identity.ts` discipline,
18
+ * for the same reason. A wrong match binds a session's work to somebody
19
+ * else's ticket.
20
+ */
21
+ /** `BLI-3654`, `TRI-12` — a team key, a hyphen, a number, and nothing else. */
22
+ const ISSUE_IDENTIFIER = /^[A-Z][A-Z0-9]{1,12}-\d+$/;
23
+ /**
24
+ * The first identifier Tower's own tracker mints. Linear's BLI team is in the
25
+ * 3,000s as of 2026-09-05 and would need six thousand more tickets to reach
26
+ * it; if it ever does, this constant moves and `work_issues.source` becomes
27
+ * the only honest discriminator.
28
+ */
29
+ export const TOWER_NATIVE_ISSUE_NUMBER_FLOOR = 10_000;
1
30
  export function parseTicketIdFromText(value) {
2
31
  const match = value.match(/\b[A-Z][A-Z0-9]{1,12}-\d+\b/);
3
32
  return match?.[0] ?? null;
4
33
  }
34
+ /** Is this the shape either tracker uses for an identifier? */
35
+ export function looksLikeIssueIdentifier(value) {
36
+ return ISSUE_IDENTIFIER.test(value.trim().toUpperCase());
37
+ }
38
+ /** The one spelling of an identifier: trimmed and upper-cased, or null. */
39
+ export function normalizeIssueIdentifier(value) {
40
+ const normalized = value.trim().toUpperCase();
41
+ return ISSUE_IDENTIFIER.test(normalized) ? normalized : null;
42
+ }
43
+ /**
44
+ * Is this an id only TOWER's tracker could have minted? A fact about the
45
+ * number, not a claim about any row: `BLI-10042` cannot be in Linear whether
46
+ * or not it is in Tower.
47
+ */
48
+ export function isTowerNativeIssueId(value) {
49
+ const match = /^[A-Z][A-Z0-9]{1,12}-(\d+)$/.exec(value.trim().toUpperCase());
50
+ return match ? Number(match[1]) >= TOWER_NATIVE_ISSUE_NUMBER_FLOOR : false;
51
+ }
52
+ /**
53
+ * The Linear id a Tower-native title mirrors: the LAST `[BLI-3779]` in the
54
+ * title, because a title may quote another ticket in its prose and the
55
+ * convention puts the mirrored id at the end.
56
+ */
57
+ export function mirroredTicketIdInTitle(title) {
58
+ const matches = [...title.matchAll(/\[([A-Z][A-Z0-9]{1,12}-\d+)\]/gi)];
59
+ const last = matches.at(-1);
60
+ return last ? last[1].toUpperCase() : null;
61
+ }
@@ -85,6 +85,8 @@ export declare const LocalWorkContextSchema: z.ZodObject<{
85
85
  started_at: z.ZodString;
86
86
  updated_at: z.ZodOptional<z.ZodString>;
87
87
  active_ticket_id: z.ZodOptional<z.ZodString>;
88
+ tower_issue_id: z.ZodOptional<z.ZodString>;
89
+ linear_ticket_id: z.ZodOptional<z.ZodString>;
88
90
  ticket_binding_candidates: z.ZodDefault<z.ZodArray<z.ZodObject<{
89
91
  ticket_id: z.ZodString;
90
92
  binding_source: z.ZodEnum<{
@@ -76,6 +76,20 @@ export const LocalWorkContextSchema = z
76
76
  started_at: IsoDateTimeSchema,
77
77
  updated_at: IsoDateTimeSchema.optional(),
78
78
  active_ticket_id: NonEmptyStringSchema.optional(),
79
+ /**
80
+ * BLI-3779, the dual-run: one piece of work has an id in TWO trackers, so
81
+ * the context carries both beside `active_ticket_id` (which stays exactly
82
+ * what the person typed — rewriting it would move every downstream
83
+ * attribution to an id nobody bound).
84
+ *
85
+ * `tower_issue_id` is a `work_issues.identifier` (`BLI-10019`);
86
+ * `linear_ticket_id` is the Linear one (`BLI-3779`). Both OPTIONAL and
87
+ * both absent when nothing was resolved: `cockpit start` never blocks a
88
+ * session on a tracker lookup (session-first commandment), so an
89
+ * unresolved ticket is a named gap, never a missing context.
90
+ */
91
+ tower_issue_id: NonEmptyStringSchema.optional(),
92
+ linear_ticket_id: NonEmptyStringSchema.optional(),
79
93
  ticket_binding_candidates: z
80
94
  .array(TicketBindingCandidateSchema)
81
95
  .default([]),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bli-cockpit/telemetry-core",
3
- "version": "0.1.29",
3
+ "version": "0.1.30",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",