atris 3.75.0 → 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.
@@ -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,