atris 3.74.29 → 3.76.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.
@@ -2,16 +2,33 @@
2
2
 
3
3
  // Why a claim was let go, as a field the rating can read without reading words.
4
4
  //
5
- // One kind exists. The work is done and its pull request is open for a person to
5
+ // Two kinds exist. Both ride on the release event as fields; the reason text is
6
+ // only for people, and nothing ever parses it.
7
+ //
8
+ // proof_not_saved. The work is done and its pull request is open for a person to
6
9
  // land, but the proof that says so could not be saved. The builder did its part,
7
- // so the release is neither a landing nor a drop. The kind and the pull request
8
- // ride on the release event as fields; the reason text is only for people, and
9
- // nothing ever parses it.
10
+ // so the release is neither a landing nor a drop. A release says this by passing
11
+ // the kind and the pull request together. The task db refuses half of a marker,
12
+ // and the rating reads a release as this kind only when both are there.
13
+ //
14
+ // could_not_start. The flight let the claim go before the engine ran, because the
15
+ // build machine could not start the job (no room on the disk, a build copy that
16
+ // would not open, a lease that would not set, a brief that would not save). The
17
+ // builder never touched the work, so the release is neither a drop nor a finished
18
+ // job. The kind goes alone, with no pull request, and only the flights pass it.
10
19
  //
11
- // A release says this by passing both fields. The task db refuses half of a
12
- // marker, and the rating reads a release as this kind only when both are there.
20
+ // The kind checks itself. A builder shares the task store with the flight, so
21
+ // the store and the rating take it only for a claim whose engine was never
22
+ // asked. Right before it asks the assigned engine, the flight writes a
23
+ // build_started event on the claim (see markBuildStarted in task-db.js). A
24
+ // release that carries could_not_start on a claim with that event is an
25
+ // ordinary release, and the rating reads it as a drop. Scout and prep passes
26
+ // run before the mark, so they never count as the build starting.
13
27
 
14
28
  const PROOF_NOT_SAVED = 'proof_not_saved';
29
+ const COULD_NOT_START = 'could_not_start';
30
+ // The event type of that mark.
31
+ const BUILD_STARTED = 'build_started';
15
32
 
16
33
  // True for a release event payload that carries the kind and an open pull
17
34
  // request it can point at. Anything less is an ordinary release.
@@ -24,4 +41,11 @@ function isProofNotSaved(payload) {
24
41
  return (Number.isInteger(pr.number) && pr.number > 0) || /^https?:\/\//i.test(String(pr.url || '').trim());
25
42
  }
26
43
 
27
- module.exports = { PROOF_NOT_SAVED, isProofNotSaved };
44
+ // True for a release event payload that carries the could-not-start kind.
45
+ // Anything else, including the same words with no field, is an ordinary release.
46
+ function isCouldNotStart(payload) {
47
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return false;
48
+ return payload.kind === COULD_NOT_START;
49
+ }
50
+
51
+ module.exports = { PROOF_NOT_SAVED, COULD_NOT_START, BUILD_STARTED, isProofNotSaved, isCouldNotStart };
@@ -59,20 +59,65 @@ function reviewEventActors(task) {
59
59
  return actors;
60
60
  }
61
61
 
62
- // Actors who reviewed the task and are not its builder.
62
+ // Everyone who ever built the task: the stamped builder, the current claimant, whoever any claim
63
+ // event on file names, and whoever handed work in on it (the proof_ready events that carry a
64
+ // handed_in_by mark; a review pass leaves none) together with the others that hand-in names as
65
+ // having built the work with it (its built_with list: a flight that ran for a member hands in under
66
+ // the member's name, and the engines that ran are named there). Authorship is cumulative and nothing clears it, so
67
+ // sending a job back, letting the claim go or reopening it never makes a past builder look
68
+ // independent again. The system's own names (RESERVED_ACTORS) record passes and checks, never
69
+ // builds, so an event under one of them makes no author. `task.events` is whatever the caller has
70
+ // of the job's history; a caller with the whole history (the store's authorsOfTask) gets the whole
71
+ // answer.
72
+ function taskAuthors(task) {
73
+ const authors = new Set();
74
+ if (!task || typeof task !== 'object') return authors;
75
+ const add = (value, { fromEvent = false } = {}) => {
76
+ const name = normalizeActor(value);
77
+ if (name && !(fromEvent && RESERVED_ACTORS.has(name))) authors.add(name);
78
+ };
79
+ const metadata = task.metadata && typeof task.metadata === 'object' ? task.metadata : {};
80
+ add(metadata.built_by);
81
+ add(task.claimed_by);
82
+ const events = Array.isArray(task.events) ? task.events : [];
83
+ for (const event of events) {
84
+ if (!event || typeof event !== 'object') continue;
85
+ const payload = event.payload && typeof event.payload === 'object' ? event.payload : {};
86
+ if (event.event_type === 'claimed') add(payload.claimed_by || event.actor, { fromEvent: true });
87
+ else if (event.event_type === 'proof_ready') {
88
+ add(payload.handed_in_by, { fromEvent: true });
89
+ // A list of names, not a string to split; anything in it that is not a name is no author.
90
+ if (Array.isArray(payload.built_with)) {
91
+ for (const name of payload.built_with) if (typeof name === 'string') add(name, { fromEvent: true });
92
+ }
93
+ }
94
+ }
95
+ return authors;
96
+ }
97
+
98
+ // Whether this actor ever built the task (see taskAuthors), or is the builder the older rules
99
+ // resolve for a row with no other record (taskBuilder).
100
+ function isTaskAuthor(task, actor) {
101
+ const name = normalizeActor(actor);
102
+ if (!name || !task || typeof task !== 'object') return false;
103
+ return taskAuthors(task).has(name) || taskBuilder(task) === name;
104
+ }
105
+
106
+ // Actors who reviewed the task and never built any of it.
63
107
  function independentReviewActors(task) {
64
108
  const builder = taskBuilder(task);
65
109
  const actors = reviewEventActors(task);
66
110
  if (builder) actors.delete(builder);
111
+ for (const author of taskAuthors(task)) actors.delete(author);
67
112
  return actors;
68
113
  }
69
114
 
70
- // True when at least one review pass came from someone other than the
71
- // builder. When the builder cannot be resolved at all, fall back to
72
- // requiring two distinct actors. Independence cannot be proven from one.
115
+ // True when at least one review pass came from someone who never built any of the task. When
116
+ // nobody can be resolved as its builder at all, fall back to requiring two distinct actors.
117
+ // Independence cannot be proven from one.
73
118
  function hasIndependentReview(task) {
74
119
  const builder = taskBuilder(task);
75
- if (!builder) return reviewEventActors(task).size >= 2;
120
+ if (!builder && taskAuthors(task).size === 0) return reviewEventActors(task).size >= 2;
76
121
  return independentReviewActors(task).size >= 1;
77
122
  }
78
123
 
@@ -138,6 +183,8 @@ module.exports = {
138
183
  normalizeActor,
139
184
  isFleetEngineActor,
140
185
  taskBuilder,
186
+ taskAuthors,
187
+ isTaskAuthor,
141
188
  reviewEventActors,
142
189
  independentReviewActors,
143
190
  hasIndependentReview,