Skip to content

Rename Artifactory to Mailroom: letters, notices, and half the rail - #284

Merged
scgopi merged 6 commits into
mainfrom
rename/mailroom
Sep 5, 2026
Merged

scgopi merged 6 commits into
mainfrom
rename/mailroom

Conversation

@scgopi

@scgopi scgopi commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Why

Artifactory named the feature after the JFrog instance the OpenAI agents improvised a board inside, in the Hugging Face incident it was drawn from. The allusion does not survive contact with a reader:

  • The vendor was the least memorable detail of that story. The coverage almost uniformly calls it "a secret message board" — the thing that stuck is the board, not the box it ran in. So the reference does not land even with people who know the incident.
  • JFrog owns the word for every developer with a build pipeline, and predicts a binary repository — the one thing this is not. The incident fades; JFrog does not.
  • The copy conceded it. The Settings toggle had to translate its own label in the first four words: Toggle("Artifactory") followed by "Loops share a message board…". The codebase says "the board" 114 times in shipped strings.

Mailroom is what the section now is. It carries both halves of a graph's traffic — addressed correspondence and unaddressed notices — and a mailroom is shared infrastructure, which is the right scope: inbox and mailbox are per-recipient, and this is one board per graph. Board was unavailable; SummaryBoard/BoardNode/BoardForm already mean the loop's diagram.

The vocabulary

The mail framing earns a lexicon the old name could not give:

Concept Was Now
The system, rail header, toggle Artifactory Mailroom
CLI namespace graphcode artifactory graphcode mail
A post addressed to nobody note notice
The room's copy of a delivered message record letter
A loop's unread view sync inbox

Nothing on disk is dropped

A rename that drops what is already stored is a data loss with a changelog entry. Every old spelling is read and none is written back:

  • artifactoryEnabled, lastArtifactoryRead, artifactoryWatch and the graph's artifactory array decode through a dynamic legacy key. Extra CodingKeys cases were the obvious route and the wrong one — LoopNode and GraphcodeSettings let the compiler synthesise encode(to:), which requires a property per case, and a legacy key must never be written or the old spelling outlives the rename in every file the app touches.
  • A legacy value that will not decode falls back to the default rather than failing the read — for a graph, ProjectPersistence turns any decode failure into "no saved graph".
  • The ramp falls back to the artifactory key. ramps.json is fetched from graphcode.app, so a build knowing only the new spelling would lose the kill switch the moment it shipped ahead of the deployed file. docs/ramps.json publishes both until it has caught up.
  • mailroom and artifactory still parse, as does sync for inbox — live loops carry the old verbs in briefings and memory logs written before today. Same aliases in the remote Python shim.

Two things that are not renames

  • maxRecords 50 → maxLetters 200. Fifty was priced as receipts for traffic that mattered elsewhere. With correspondence half of what the room is for, a ten-way fanout spent the budget in one pass and evicted the history the next loop joins to read — the failure the separate budgets existed to prevent. Level with the notices, still pruned apart.
  • The section takes half the rail (was 40%), floor 200, ceiling 820. At four visible posts on a laptop it was a section you had to scroll before it told you anything. Still a share and not a fixed height, so the Artifactory rail: the board takes a share of the rail, never enough to push the foot off #245 invariant holds: at the shortest rail a 1280×800 window produces, the room plus everything rigid above it is 660 of 700 points, pinned by MailroomRailShareTests.

Verification

  • MailroomLegacyNamesTests covers what an old install still has and what its loops still type: the recorded off-choice, the board, a loop's cursor and watch, both Kind spellings, an unknown kind reading as a notice rather than losing the board, the ramp key, and all three verb spellings.
  • 1584 tests / 163 suites pass (was 1577/162). swiftlint 0 errors; swift-format --strict clean. All three schemes build (graphcode, graphcode-cli, graphcoded), plus swift build for the Linux CI path.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AtVtkzZNE5fLPeHVqM7A3K

scgopi and others added 6 commits September 4, 2026 21:08
Artifactory named the feature after the JFrog instance the OpenAI agents
improvised a board inside, in the Hugging Face incident it was drawn from.
The allusion does not survive contact with a reader: the vendor was the
least memorable detail of that story (the coverage almost uniformly calls
it "a secret message board"), while JFrog owns the word for every
developer with a build pipeline, and predicts a binary repository — the
one thing this is not.

Mailroom is what the section actually is now that it carries both halves
of a graph's traffic: addressed correspondence (node send, message edges,
handoffs) and unaddressed notices left for whoever comes next. A mailroom
is shared infrastructure, which is the right scope — inbox and mailbox
are per-recipient, and this is one board per graph. Board was unavailable:
SummaryBoard/BoardNode/BoardForm already mean the loop's diagram.

Blanket identifier rename; compatibility follows in the next commits.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AtVtkzZNE5fLPeHVqM7A3K
The mail framing earns a lexicon the old name could not: a post addressed
to nobody is a notice, the room's copy of a delivered message is a letter.
`Kind.note`/`.record` rename to match, decoding the old spellings — an
unrecognised kind reads as a notice rather than throwing, because
ProjectPersistence turns any decode failure into "no saved graph" and a
strict reading would trade one unknown post for the whole board.

maxRecords 50 -> maxLetters 200. Fifty was priced as receipts for traffic
that mattered elsewhere; with correspondence half of what the room is for,
a ten-way fanout spent the budget in one pass and evicted the history the
next loop joins to read. Level with the notices, still pruned apart, so
neither kind of traffic can crowd out the other.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AtVtkzZNE5fLPeHVqM7A3K
…erbs

A rename that drops what is already on disk is a data loss with a
changelog entry. Every persisted Artifactory spelling is still read, and
none is written back:

- artifactoryEnabled, lastArtifactoryRead, artifactoryWatch and the
  graph's artifactory array decode through a dynamic legacy key. Extra
  CodingKeys cases were the obvious route and the wrong one — LoopNode
  and GraphcodeSettings let the compiler synthesise encode(to:), which
  requires a property per case, and a legacy key must never be written
  or the old spelling outlives the rename in every file we touch. A
  legacy value that will not decode falls back to the default rather
  than failing the read: for a graph that is "no saved graph".
- The ramp falls back to the artifactory key. ramps.json is fetched from
  graphcode.app, so a build knowing only the new spelling would lose the
  kill switch the moment it shipped ahead of the deployed file;
  docs/ramps.json publishes both until it has.
- `graphcode mail` is the verb; `mailroom` and `artifactory` are
  accepted and undocumented, as `inbox` is now the verb and `sync` the
  alias. Live loops carry the old spellings in briefings and memory logs
  written before today. Same aliases in the remote Python shim.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AtVtkzZNE5fLPeHVqM7A3K
The section was sized when it held notices alone: 40% of the rail, capped
at 600pt. Now that a graph's correspondence lands here too, a laptop rail
showed about four posts, which makes a section you have to scroll before
it tells you anything — and the point of putting the room in the rail was
that a coordination channel the supervisor never sees is the failure mode
it was drawn from.

Half the rail, floor 200 (two posts rather than a sliver), ceiling 820
(about fourteen). Still a share and not a fixed height, so the #245
invariant holds: at the shortest rail a 1280x800 window produces, the
room plus everything rigid above it comes to 660 of 700 points, and
MailroomRailShareTests pins it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AtVtkzZNE5fLPeHVqM7A3K
The Settings copy used to translate its own label in the first four words
("Artifactory" -> "Loops share a message board"), which was the clearest
evidence the name was not carrying. It now describes the thing: letters
are what the loops said to each other, notices are addressed to nobody.
The briefing and CLI help follow the same two words.

MailroomLegacyNamesTests covers what a machine running the old build
still has on disk and what its loops still type: a recorded choice to
turn the board off, the board itself, a loop's cursor and watch, both
Kind spellings, an unknown kind reading as a notice instead of losing the
board, the ramp key, and all three verb spellings. Each encodes the
current shape and rewrites the keys back rather than hand-writing JSON,
so the tests pin the key lookup and not a date strategy.

1584 tests / 163 suites pass (was 1577/162); swiftlint 0 errors,
swift-format --strict clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AtVtkzZNE5fLPeHVqM7A3K
The rename audit turned up copy the blanket pass could not catch, because
none of it contains the word "Artifactory" — it was stale in the other
direction:

- The MAILROOM help section still taught `sync`, which is now the alias
  and not the verb. A help page naming a verb the help page above it does
  not list is worse than either spelling on its own.
- `mail post` advertised `<note…>` in the CLI help, the briefing, the
  shim's help, and the end-of-run ask. The argument is a notice.
- "the board is empty" became "the room is empty" on both renderers, and
  RemoteCLIShimTests caught the shim's `<note…>` before it shipped — the
  byte-equality rule earning its keep.
- The mirrored-traffic paragraph now calls them letters.

Left alone deliberately: "board" as an informal noun in comments and in
prose about the notices half. A mailroom has a board on its wall, and
rewriting 114 occurrences would be churn with no reader on the other end.

1584 tests / 163 suites pass; swiftlint 0 errors, swift-format --strict
clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AtVtkzZNE5fLPeHVqM7A3K
@scgopi
scgopi merged commit 731ac3a into main Sep 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant