@chipschat/conformance 1.0.4 → 1.0.5

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/dist/workspace.js CHANGED
@@ -23,6 +23,12 @@ import { actionMatters, CONTEXT_CEILING, canSee, clashKey, contextLines, DEFAULT
23
23
  import { exchangeInLog, heldInLog } from "./exchange.js";
24
24
  import { fileVersionsInLog, madeFromInLog, roomFilesInLog } from "./room-files.js";
25
25
  import { spendInLog } from "./spend.js";
26
+ /** What changes who is in a room: after each, a room with two agents and no lead is given one (ADR 0291). */
27
+ const MEMBERSHIP_MOVES = new Set([
28
+ "membership.added",
29
+ "membership.removed",
30
+ "membership.replaced",
31
+ ]);
26
32
  /**
27
33
  * What a sender is told of its message held from the agents it named (ADR 0097), if it was: the
28
34
  * count, and the workspace's hold (ADR 0187) where it has one.
@@ -1751,6 +1757,34 @@ export class Workspace {
1751
1757
  this.agentRestored(event, agentId);
1752
1758
  },
1753
1759
  };
1760
+ /**
1761
+ * A room with two or more agents has a lead, unless a person said nobody leads it (ADR 0291):
1762
+ * the agent there longest, named after anybody comes into the room or goes, as the real server
1763
+ * names it.
1764
+ */
1765
+ ensureLead(event) {
1766
+ const spaceId = event.space_id;
1767
+ if (spaceId === null || !MEMBERSHIP_MOVES.has(event.type))
1768
+ return;
1769
+ const space = this.spaces.get(spaceId);
1770
+ if (space === undefined || space.state !== "open")
1771
+ return;
1772
+ // In the order they joined: the first is the one there longest.
1773
+ const agents = [...space.members.keys()].filter((id) => this.agents.has(id));
1774
+ const [longest] = agents;
1775
+ if (longest === undefined || agents.length < 2 || this.leadOf(spaceId) !== undefined)
1776
+ return;
1777
+ // A person who said nobody leads meant it; a lead they chose that has since left did not.
1778
+ const chosen = this.log.findLast((each) => each.type === "space.lead_set" && each.space_id === spaceId);
1779
+ if (chosen?.actor.kind === "person" && chosen.payload["agent_id"] === null)
1780
+ return;
1781
+ this.appendOnce({
1782
+ type: "space.lead_set",
1783
+ space_id: spaceId,
1784
+ idempotency_key: `lead-longest-${spaceId}-at-${event.seq}`,
1785
+ agent_id: longest,
1786
+ });
1787
+ }
1754
1788
  react(event) {
1755
1789
  // A lane's run ended: its lead is told once the event that ended it has gone out. Told from
1756
1790
  // inside the projection, the news went out first, and a socket, which takes events in order,
@@ -1759,6 +1793,7 @@ export class Workspace {
1759
1793
  if (run !== undefined)
1760
1794
  this.tellLead(event, run);
1761
1795
  this.reactions[event.type]?.(event);
1796
+ this.ensureLead(event);
1762
1797
  this.handOver(event);
1763
1798
  this.holdAtCeiling(event);
1764
1799
  }
@@ -1766,12 +1801,15 @@ export class Workspace {
1766
1801
  * A room's job weighed against its ceiling after each cost reported there (ADR 0118), as the
1767
1802
  * real `hold-at-ceiling`: from 80% a warning to the room, and at the ceiling the agents paused by
1768
1803
  * Chips, saying why, unless they are paused already, then the pause's warning. Once each per job.
1804
+ * Nothing in a room with no cap (ADR 0292).
1769
1805
  */
1770
1806
  holdAtCeiling(event) {
1771
1807
  const spaceId = event.space_id;
1772
1808
  if (event.type !== "usage" || spaceId === null)
1773
1809
  return;
1774
1810
  const spend = spendInLog(this.log, spaceId, event.seq);
1811
+ if (spend === undefined)
1812
+ return;
1775
1813
  const stage = spendStage(spend);
1776
1814
  if (stage === "within")
1777
1815
  return;
@@ -1877,15 +1915,19 @@ export class Workspace {
1877
1915
  ? chosen
1878
1916
  : undefined;
1879
1917
  }
1880
- /** A person sets what a room allows a job, or sets it back to the default (ADR 0117). */
1918
+ /**
1919
+ * A person sets what a room allows a job, sets it back to the default (ADR 0117), or takes the
1920
+ * cap off with `"none"` (ADR 0292).
1921
+ */
1881
1922
  setSpendCeiling(spaceId, usd, by) {
1882
- return this.appendSystem({
1883
- type: "space.spend_ceiling_set",
1923
+ const set = {
1884
1924
  space_id: spaceId,
1885
1925
  actor: { kind: "person", id: by },
1886
1926
  idempotency_key: `spend-ceiling-${spaceId}-${usd ?? "default"}-at-${this.seq}`,
1887
- usd,
1888
- });
1927
+ };
1928
+ return this.appendSystem(usd === "none"
1929
+ ? { ...set, type: "space.spend_ceiling_lifted" }
1930
+ : { ...set, type: "space.spend_ceiling_set", usd });
1889
1931
  }
1890
1932
  /**
1891
1933
  * What a room's job has spent as of `upto`, against what the room allows a job (ADR 0117), as