@finbheara/archive-client 0.35.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -103,6 +103,7 @@ c.features; // [{ feature: "dancers", state: "full" | "missing", missing: [...
103
103
  | `calendar` | `calendar.get`, `calendar.list` | 320 |
104
104
  | `calendar.expected` | each calendar stage's `expected`; absent, never refused, without it | 320 |
105
105
  | `calendar.next` | `calendar.next` | 320 |
106
+ | `calendar.missing` | `calendar.missing` | 320 |
106
107
  | `tabs`, `panels` | `tabs.query`, `tabs.stream`; `panels.query` | 184 |
107
108
  | `feis-panels` | `feisPanels.query` | 260 |
108
109
  | `staff.adjudicators` | `staff.adjudicators` | 230 |
@@ -772,6 +773,10 @@ const l = await rel.calendar.list({ stage: "entrants", state: "observed", from:
772
773
  const n = await rel.calendar.next({ brand: "plf" });
773
774
  // [{ feis_brand_id, year, run_expected, run_expected_basis, run_expected_n,
774
775
  // from_instance_id, from_date }]: a series' next edition no listing names yet
776
+ const m = await rel.calendar.missing({ stage: "results", kind: "platform-host" });
777
+ // stage, platform, tier, kind; { items: [{ item_id, stage, feis_instance_id, kind,
778
+ // platform, expected, expected_basis, expected_n, grace_days, due, overdue_days,
779
+ // hosts: [{ source, feis_id, url }], ... }], deferred }
775
780
  ```
776
781
 
777
782
  ONE ROW PER FEIS INSTANCE, on the id its results carry: a feis-series instance (`<brand>.<year>`),
@@ -802,6 +807,18 @@ held years, the last the release's year or the one before, whose next edition is
802
807
  calendar: its year and expected first day. It is never an instance: an id is minted only once a
803
808
  listing names the edition.
804
809
 
810
+ THE MISSING STAGES (`calendar.missing`): a `results` or `entrants` stage no capture has shown whose
811
+ expected day plus its platform's GRACE is before the release's day, the run inside the 365 days
812
+ before it. The grace is the platform's largest gap between two days it was captured on, over the
813
+ 180 days before the release, at least 7 days: an item waits out the platform's slowest scrape
814
+ before it counts; a day on the pooled lag (basis `pooled`), or a platform with no gap of its own,
815
+ waits the pooled grace. A stage whose basis is `unmeasured` is never missing. An item is a calendar
816
+ instance, or a feis-index listing no instance holds (`feis_instance_id` null, `item_id` its first
817
+ occurrence id). `kind` is `platform-host` (a capture platform lists it, so a scrape of it should
818
+ bring it) or `listing-only` (only a calendar listing names it, no capture platform, and its results
819
+ may be published nowhere capture reads). A stage a capture's not-found record defers is not listed:
820
+ `deferred` counts those. A worklist, never an error.
821
+
805
822
  ## Teachers and adjudicators
806
823
 
807
824
  ```ts
@@ -981,6 +998,8 @@ is passed to the dancer resolver as asked (`rel.dancers`, above).
981
998
  idq calendar [--brand <series>] [--tier <t>] [--from <date>] [--to <date>] [--stage <s>] [--state <s>]
982
999
  [--terminal results|withdrawn|passed-no-results|none]
983
1000
  idq calendar --next [--brand <series>]
1001
+ idq calendar --missing [--stage results|entrants] [--platform <p>] [--tier <t>]
1002
+ [--kind platform-host|listing-only]
984
1003
  idq teacher [--release <spec>] <name|TD number>
985
1004
  idq adjudicator [--release <spec>] <name|TD number>
986
1005
  idq comp [--release <spec>] <feis> <code> [--year y] [--title t]
@@ -742,6 +742,33 @@ var FEATURES2 = [
742
742
  since: 320,
743
743
  calls: "calendar.next"
744
744
  },
745
+ {
746
+ feature: "calendar.missing",
747
+ needs: [
748
+ "item_id",
749
+ "stage",
750
+ "feis_instance_id",
751
+ "feis_brand_id",
752
+ "tier",
753
+ "name_printed",
754
+ "date_lo",
755
+ "date_hi",
756
+ "occurrence_ids",
757
+ "feis_ids",
758
+ "kind",
759
+ "platform",
760
+ "expected",
761
+ "expected_basis",
762
+ "expected_n",
763
+ "grace_days",
764
+ "due",
765
+ "overdue_days",
766
+ "hosts",
767
+ "deferred"
768
+ ].map((c) => `results:feis_calendar_missing.${c}`),
769
+ since: 320,
770
+ calls: "calendar.missing"
771
+ },
745
772
  {
746
773
  feature: "upcoming.entrants",
747
774
  needs: [
@@ -3968,6 +3995,52 @@ class CalendarFinder2 {
3968
3995
  }))
3969
3996
  };
3970
3997
  }
3998
+ async missing(q = {}) {
3999
+ await this.rel.fetch("results");
4000
+ await this.rel.require("calendar.missing");
4001
+ const db = this.rel.db("results");
4002
+ const where = [];
4003
+ const args = [];
4004
+ for (const [col, v] of [
4005
+ ["stage", q.stage],
4006
+ ["platform", q.platform],
4007
+ ["tier", q.tier],
4008
+ ["kind", q.kind]
4009
+ ])
4010
+ if (v !== undefined) {
4011
+ where.push(`${col} = ?`);
4012
+ args.push(v);
4013
+ }
4014
+ const rows = db.query(`SELECT * FROM feis_calendar_missing${where.length === 0 ? "" : ` WHERE ${where.join(" AND ")}`}
4015
+ ORDER BY CASE stage WHEN 'results' THEN 0 ELSE 1 END,
4016
+ CASE kind WHEN 'platform-host' THEN 0 ELSE 1 END, platform, due, item_id`).all(...args);
4017
+ const live = rows.filter((r) => r.deferred === null || r.deferred === undefined);
4018
+ return {
4019
+ tag: this.rel.tag,
4020
+ items: live.map((r) => ({
4021
+ item_id: r.item_id,
4022
+ stage: r.stage,
4023
+ feis_instance_id: r.feis_instance_id ?? null,
4024
+ feis_brand_id: r.feis_brand_id ?? null,
4025
+ tier: r.tier,
4026
+ name_printed: r.name_printed ?? null,
4027
+ date_lo: r.date_lo ?? null,
4028
+ date_hi: r.date_hi ?? null,
4029
+ occurrence_ids: json(r.occurrence_ids, []),
4030
+ feis_ids: json(r.feis_ids, []),
4031
+ kind: r.kind,
4032
+ platform: r.platform,
4033
+ expected: r.expected,
4034
+ expected_basis: r.expected_basis,
4035
+ expected_n: r.expected_n === null || r.expected_n === undefined ? null : Number(r.expected_n),
4036
+ grace_days: Number(r.grace_days),
4037
+ due: r.due,
4038
+ overdue_days: Number(r.overdue_days),
4039
+ hosts: json(r.hosts, [])
4040
+ })),
4041
+ deferred: rows.length - live.length
4042
+ };
4043
+ }
3971
4044
  async get(id) {
3972
4045
  const db = await this.db();
3973
4046
  const ways = [
package/dist/cli.js CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  latestCheck2,
22
22
  within,
23
23
  staleWarning2
24
- } from "./chunks/index-gt7yxxp8.js";
24
+ } from "./chunks/index-c08q1b0d.js";
25
25
  import"./chunks/index-hghdy980.js";
26
26
 
27
27
  var USAGE_HEADER = "usage: idq <verb> [--cache <dir>] [--repo <owner/name>] [--json] [--live]";
@@ -394,8 +394,19 @@ var VERBS = [
394
394
  },
395
395
  {
396
396
  verb: "calendar",
397
- value: ["--release", "--brand", "--tier", "--from", "--to", "--stage", "--state", "--terminal"],
398
- bool: ["--next"],
397
+ value: [
398
+ "--release",
399
+ "--brand",
400
+ "--tier",
401
+ "--from",
402
+ "--to",
403
+ "--stage",
404
+ "--state",
405
+ "--terminal",
406
+ "--platform",
407
+ "--kind"
408
+ ],
409
+ bool: ["--next", "--missing"],
399
410
  usage: [
400
411
  " calendar [--release <spec>] <instance|feis id|occurrence id>",
401
412
  " one feis instance's stages: announced, syllabus, entrants,",
@@ -408,7 +419,12 @@ var VERBS = [
408
419
  " expected day with its basis and n where the release has them",
409
420
  " calendar --next [--brand <series>]",
410
421
  " each series' next edition no listing names yet: its year",
411
- " and expected first day from the year before (basis brand)"
422
+ " and expected first day from the year before (basis brand)",
423
+ " calendar --missing [--stage results|entrants] [--platform <p>] [--tier T1..T4]",
424
+ " [--kind platform-host|listing-only]",
425
+ " the stages past their expected day plus the platform's",
426
+ " grace, the run in the last 365 days: hosts, urls, expected",
427
+ " day, grace and days overdue; the deferred counted apart"
412
428
  ]
413
429
  },
414
430
  {
@@ -1558,6 +1574,27 @@ async function main(argv, io = {}) {
1558
1574
  const rel = await open(spec, { ...opts, assets: [] });
1559
1575
  try {
1560
1576
  const line = (e) => ` ${e.date_lo ?? "?"} ${e.feis_instance_id} ${e.tier} ${["announced", "syllabus", "entrants", "run", "results"].map((s) => `${s}:${e.stages[s].state === "observed" ? e.stages[s].date ?? "seen" : e.stages[s].state}`).join(" ")} [${e.terminal ?? "ahead"}]${e.name_printed !== null ? ` "${e.name_printed}"` : ""}`;
1577
+ if (p.bools.has("--missing")) {
1578
+ const stage = p.flags.get("--stage");
1579
+ const platform = p.flags.get("--platform");
1580
+ const tier = p.flags.get("--tier");
1581
+ const kind = p.flags.get("--kind");
1582
+ const a = await rel.calendar.missing({
1583
+ ...stage !== undefined ? { stage } : {},
1584
+ ...platform !== undefined ? { platform } : {},
1585
+ ...tier !== undefined ? { tier } : {},
1586
+ ...kind !== undefined ? { kind } : {}
1587
+ });
1588
+ out(a, () => {
1589
+ for (const m of a.items) {
1590
+ say(` ${m.due} ${m.item_id} ${m.stage} ${m.kind} ${m.platform} run ${m.date_lo ?? "?"} expected ${m.expected} (${m.expected_basis}, n ${m.expected_n ?? "-"}) + ${m.grace_days} grace ${m.overdue_days} days overdue${m.name_printed !== null ? ` "${m.name_printed}"` : ""}`);
1591
+ for (const h of m.hosts)
1592
+ say(` ${h.source} ${h.feis_id ?? "-"} ${h.url ?? "-"}`);
1593
+ }
1594
+ say(`${a.items.length} missing, ${a.deferred} deferred, in ${a.tag}`);
1595
+ });
1596
+ return a.items.length === 0 ? 1 : 0;
1597
+ }
1561
1598
  if (p.bools.has("--next")) {
1562
1599
  const brand = p.flags.get("--brand");
1563
1600
  const a = await rel.calendar.next(brand === undefined ? {} : { brand });
package/dist/index.js CHANGED
@@ -80,7 +80,7 @@ import {
80
80
  readLatestCheck2,
81
81
  latestCheck2,
82
82
  staleWarning2
83
- } from "./chunks/index-gt7yxxp8.js";
83
+ } from "./chunks/index-c08q1b0d.js";
84
84
  import {
85
85
  cacheRoot2,
86
86
  repoOf2
@@ -59,6 +59,45 @@ export interface CalendarNextAnswer {
59
59
  tag: string;
60
60
  next: CalendarNext[];
61
61
  }
62
+ export type CalendarMissingStage = "results" | "entrants";
63
+ export type CalendarMissingKind = "platform-host" | "listing-only";
64
+ export interface CalendarMissingHost {
65
+ source: string;
66
+ feis_id: string | null;
67
+ url: string | null;
68
+ }
69
+ export interface CalendarMissing {
70
+ item_id: string;
71
+ stage: CalendarMissingStage;
72
+ feis_instance_id: string | null;
73
+ feis_brand_id: string | null;
74
+ tier: string;
75
+ name_printed: string | null;
76
+ date_lo: string | null;
77
+ date_hi: string | null;
78
+ occurrence_ids: string[];
79
+ feis_ids: string[];
80
+ kind: CalendarMissingKind;
81
+ platform: string;
82
+ expected: string;
83
+ expected_basis: CalendarExpectedBasis;
84
+ expected_n: number | null;
85
+ grace_days: number;
86
+ due: string;
87
+ overdue_days: number;
88
+ hosts: CalendarMissingHost[];
89
+ }
90
+ export interface CalendarMissingQuery {
91
+ stage?: CalendarMissingStage;
92
+ platform?: string;
93
+ tier?: string;
94
+ kind?: CalendarMissingKind;
95
+ }
96
+ export interface CalendarMissingAnswer {
97
+ tag: string;
98
+ items: CalendarMissing[];
99
+ deferred: number;
100
+ }
62
101
  export interface CalendarGetAnswer {
63
102
  tag: string;
64
103
  asked: string;
@@ -74,6 +113,7 @@ export declare class CalendarFinder {
74
113
  next(q?: {
75
114
  brand?: string;
76
115
  }): Promise<CalendarNextAnswer>;
116
+ missing(q?: CalendarMissingQuery): Promise<CalendarMissingAnswer>;
77
117
  get(id: string): Promise<CalendarGetAnswer>;
78
118
  list(q?: CalendarQuery): Promise<CalendarAnswer>;
79
119
  }
@@ -26,5 +26,5 @@ export { type EntryRow, type StreamCompetition, type StreamQuery, type StreamRow
26
26
  export { type FeisPanelSeat, FeisPanelFinder, PanelFinder, type PanelSeat, type RegisterRow, type TabAnswer, TabFinder, type TabQuery, type TabRow, type TabStreamQuery, } from "./tabs.js";
27
27
  export { EventFinder, type EventYear, type EventYearQuery, type ResultRoster, type RosterMember, type RosterTeam, TeamFinder, type TeamResult, } from "./teams.js";
28
28
  export { type EntrantCandidate, FIELD_STATES, type FieldComp, DEPARTURE_REASONS, type DepartureReason, type FieldState, type HeldOut, type UpcomingDeparture, type UpcomingDepartureAnswer, type UpcomingDepartureQuery, type UpcomingEntrant, type UpcomingEntrantAnswer, type UpcomingEntrantQuery, type UpcomingFeis, type UpcomingFeisAnswer, type UpcomingFeisQuery, type UpcomingFeisState, type UpcomingField, type UpcomingFieldAnswer, type UpcomingFieldQuery, UpcomingFinder, type UpcomingHost, } from "./upcoming.js";
29
- export { CALENDAR_STAGES, CALENDAR_STAGE_STATES, CALENDAR_TERMINALS, type CalendarAnswer, type CalendarEntry, type CalendarExpected, type CalendarExpectedBasis, type CalendarNext, type CalendarNextAnswer, CalendarFinder, type CalendarGetAnswer, type CalendarQuery, type CalendarStage, type CalendarStageState, type CalendarStageValue, type CalendarTerminal, } from "./calendar.js";
29
+ export { CALENDAR_STAGES, CALENDAR_STAGE_STATES, CALENDAR_TERMINALS, type CalendarAnswer, type CalendarEntry, type CalendarExpected, type CalendarExpectedBasis, type CalendarMissing, type CalendarMissingAnswer, type CalendarMissingHost, type CalendarMissingKind, type CalendarMissingQuery, type CalendarMissingStage, type CalendarNext, type CalendarNextAnswer, CalendarFinder, type CalendarGetAnswer, type CalendarQuery, type CalendarStage, type CalendarStageState, type CalendarStageValue, type CalendarTerminal, } from "./calendar.js";
30
30
  export { ARCHIVE_TAG, type ArchiveTag, type ReleaseSpec, compareTagsNewestFirst, cutOf, parseArchiveTag, parseReleaseSpec, pickTag, renderArchiveTag, } from "./tag.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finbheara/archive-client",
3
- "version": "0.35.0",
3
+ "version": "0.36.0",
4
4
  "description": "Open a versioned release of an Irish dance results archive: download, verify, decompress and cache it by tag, keep the cache, and resolve feises and schools against it",
5
5
  "keywords": ["irish-dance", "results", "release", "cache", "sqlite"],
6
6
  "license": "MIT",