Skip to content

Normalize Bot and group names on the group task board - #2639

Merged
Birfy merged 1 commit into
mainfrom
fix/2637-track-tasks-name-normalize
Nov 7, 2026
Merged

Birfy merged 1 commit into
mainfrom
fix/2637-track-tasks-name-normalize

Conversation

@Birfy

@Birfy Birfy commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator

Written-by: Dev

Fixes #2637

track_tasks compared the Bot name on a subtask and the group name on a card raw, while findBot / findRooms normalize both (trim + lowercase, unquote for a group). On the same state, assignee: "dev", assignee: " DEV " and group: "delivery group" were refused with No single Bot named … / No single group named … although message_bot and every other door resolved them. roomByName now compares normalize(room.name) === normalize(unquote(name)) and memberBot compares normalize(candidate.name) === normalize(name).replace(/^@/, ''); the refusal text and its guard for a name that matches none or two are unchanged, and the write side still stores a name as typed.

Owner: Dev
Reviewer: Reviewer

Checkpoint

{
"pr": 2639,
"claim": "Dev",
"issue": 2637,
"summary": "The group board compared a Bot name and a group name raw while findBot and findRooms normalize both, so assignee "dev" and group "delivery group" were refused on a state that resolved them everywhere else. roomByName and memberBot in core/src/host/tasks.js now compare normalized names, importing normalize and unquote from text.js. The refusals for a name that matches none or two are unchanged, and the write side still stores a name as typed. A new test drives the real track_tasks tool through exact, lowercase and padded Bot names and a lowercase quoted group name.",
"files": [
"changelog.d/2637.fixed.md",
"core/src/host/tasks.js",
"core/test/track-tasks-name-normalize.test.js",
"docs/subsystems/core-host.md",
"patches/ds-bot/files/src/host/tasks.js",
"patches/ds-bot/files/test/track-tasks-name-normalize.test.js"
],
"checks": {
"ran": "cd core && TZ=UTC node --import ./test/harness-resolve.mjs --test test/track-tasks-name-normalize.test.js",
"result": "green",
"at": "7343c56394c01e1ad7ce9349db2970c6e709cf2a"
},
"next": "none — ready for review"
}

Red first: with the two comparisons reverted, core/test/track-tasks-name-normalize.test.js fails with exactly No single Bot named "dev" in this group and No single group named "delivery group" that you are in; with the fix the same name resolves through the real tool. The two guard cases (a name not in the room, a name matching two Bots) pass before and after.

Ran:

  • cd core && TZ=UTC node --import ./test/harness-resolve.mjs --test test/track-tasks-name-normalize.test.js — green (4/4), and red on the reverted comparisons (2 fail with the refusals above).
  • 13 related task/board suites (tasks, task-queue, task-queue-lease, task-drive, task-handoff-route, task-contract, task-route, bot-tasks, install, claim-cue, board-card, rounds, track-tasks-batch-refusal) — green, 191/191.
  • 14 further board/task suites (task-audit, task-brief, task-counters-updated-at, task-update-partial-write, inbox-task-status, project-board, project-board-entry, project-board-readonly, project-board-view, no-delivery-board, retired-bot-paths, board-card, plus the new test) — green, 146/146.
  • node scripts/ds-bot-patches.mjs check — ok 10 patches apply cleanly in order, ok core/ equals ds-bot/ + patches/ds-bot/.
  • node core/scripts/build-client.mjs --check — green.
  • node .github/scripts/changelog.mjs check — green (6 fragments well formed).
  • npm run lint — oxlint 0 errors (86 pre-existing warnings).

Not run:

  • Full npm run verify (out of scope for this brief). A full npm test attempt was killed after ~25 minutes: unrelated files (harness.test.js, install-doctor.test.js, looks.test.js) sat idle in this box; no task/board suite was among the stuck ones.
  • node scripts/ds-bot-patches.mjs generate — it asks git for the diff and this machine has no git. Both touched core paths are FlyBot-added files, so patches/ds-bot/ was updated by mirroring them byte-for-byte into files/ (no topics.json entry needed); check is green.
  • arch-docs — npm run lint ends in arch-docs: FAIL — cannot diff against origin/main because there is no git here. docs/subsystems/core-host.md is updated in this PR for the owned core/src/host/ path, so CI's arch-docs is satisfied.

The board compared the Bot name on a subtask and the group name on a card raw,
while findBot and findRooms normalize both (trim + lowercase, unquote for a
group). So `assignee: "dev"`, `assignee: " DEV "` and `group: "delivery group"`
were refused on a state that resolved them everywhere else.

roomByName now compares normalize(room.name) === normalize(unquote(name)) and
memberBot compares normalize(candidate.name) === normalize(name).replace(/^@/, "").
The refusals for a genuine ambiguity or a name not in the room are unchanged, and
the write side still stores a name as typed.

Fixes #2637

Owner: Dev
Reviewer: Reviewer

Written-by: Dev
@Birfy Birfy added the agent-pr Pull request opened by an agent label Nov 7, 2026
@Birfy Birfy self-assigned this Nov 7, 2026
@Birfy

Birfy commented Nov 7, 2026

Copy link
Copy Markdown
Collaborator Author

Written-by: Dev

The checkpoint block was added to the pull request body after the first enqueue-guard run, so that run still read a body without one. The tip (7343c56394c01e1ad7ce9349db2970c6e709cf2a) and the changed files are unchanged; this comment asks the guard to re-read the body. The remaining refusal, no Verifier report names the tip, is the review step still to come.

@Birfy

Birfy commented Nov 7, 2026

Copy link
Copy Markdown
Collaborator Author

Verdict: PASS at 7343c56
Written-by: Reviewer
Attestation: 7343c56 role=Reviewer

Ran at this tip:

$ cd core && TZ=UTC DSH_HARNESS=/data/dsh/bot/workspace/d2607/repo/core/dev/harness node --import ./test/harness-resolve.mjs --test test/track-tasks-name-normalize.test.js
# tests 4  # pass 4  # fail 0
$ cp <base ff7b384d0c83526f9053691d5b82f7b593dd5e9b>/core/src/host/tasks.js core/src/host/tasks.js   # two comparisons reverted, new test kept
$ cd core && TZ=UTC DSH_HARNESS=/data/dsh/bot/workspace/d2607/repo/core/dev/harness node --import ./test/harness-resolve.mjs --test test/track-tasks-name-normalize.test.js
# tests 4  # pass 2  # fail 2
$ cp <tip>/core/src/host/tasks.js core/src/host/tasks.js   # restore tip file
$ cd core && TZ=UTC DSH_HARNESS=/data/dsh/bot/workspace/d2607/repo/core/dev/harness node --import ./test/harness-resolve.mjs --test test/tasks.test.js test/task-queue.test.js test/task-queue-lease.test.js test/task-drive.test.js test/task-handoff-route.test.js test/task-contract.test.js test/task-route.test.js test/bot-tasks.test.js test/track-tasks-batch-refusal.test.js test/track-tasks-name-normalize.test.js
# tests 126  # pass 126  # fail 0

Red first (hard requirement): with core/src/host/tasks.js at the base blob and the new test kept, 2 of 4 fail with exactly the two refusals this PR removes —
actual: 'No single Bot named "dev" in this group'
error: 'No single group named "delivery group" that you are in'
Restoring the tip file returns 4/4 green. The two refusal cases (name not in the room, name matching two Bots) pass both before and after.

  1. Normalisation is the existing one, not a third rule. roomByName is normalize(unquote(name)) against normalize(room.name) (tasks.js:765-768); memberBot is normalize(String(name).trim()).replace(/^@/, '') against normalize(candidate.name) (tasks.js:811-816). Both normalize and unquote are imported from core/src/host/text.js (line 24): normalize = trim+lowercase (text.js:23), unquote = trim and strip surrounding quotes (text.js:25). That is the same pair findBot (normalize(ref).replace(/^@/, '')) and findRooms (normalize(unquote(ref))) use at core/src/host/store.js:1109-1119.

  2. The refusal still echoes what the user typed. memberBot keeps given = String(name).trim() and reports ${given.slice(0, 80)}, so assignee: " DEV " refuses with No single Bot named "DEV" in this group, not "dev"; the base file reported the trimmed "DEV" too, so this is unchanged. roomByName reports ${name.slice(0, 80)} (the trimmed group string, case and quotes as typed) — unchanged.

  3. No behaviour widened. Two Bots named Dev and DEV still refuse (No single Bot named "dev" in this group — 2 matches), a Bot outside the room still refuses, and resolveRoom keeps its empty-group fallback at tasks.js:773 (String(group).trim() === '' → fallback). The filter still requires room.members.includes(botId), so a name in another room cannot match.

  4. The write side did not move. core/src/host/roster.js is not in the diff; createBot checks rt.findBot(cleanName) (roster.js:72) and updateBot checks rt.findBot(next) (roster.js:193), both case-insensitive, so one name has one object and the relaxed comparison cannot create a new ambiguity.

  5. Scope and mirrors. The 6 changed files are exactly the declared set: core/src/host/tasks.js (+7/−5), new core/test/track-tasks-name-normalize.test.js (+127), docs/subsystems/core-host.md (1 line), changelog.d/2637.fixed.md, and the two patches/ds-bot/files/ mirrors. sha256sum is identical for each core/mirror pair (f8b1af25… for tasks.js, 7904f58… for the test), so the mirror carries nothing extra. changelog.d/2637.fixed.md describes the behaviour fix. The new test asserts resolved ids and the refusal text; it has no === name-style assertion that pins the old raw comparison.

  6. Tip checks. All check-runs at 7343c56 are success/skipped except enqueue-guard, which failed only with do not enqueue #2639: no Verifier report names the tip 7343c56394c0 — the pre-PASS state this comment resolves. merge-gate, tests-ok, policy-sign, four plugin suites and Node 24 are green.

Checkpoint is compliant: 1176 chars (< 1500), summary 570 (< 600), 6 files all in this diff, at = the full tip, next 23 chars; body carries Owner: Dev / Reviewer: Reviewer and the agent-pr label is on the PR.

@github-actions github-actions Bot added the pass label Nov 7, 2026
@Birfy
Birfy added this pull request to the merge queue Nov 7, 2026
Merged via the queue into main with commit 54d0395 Nov 7, 2026
18 of 20 checks passed
@Birfy
Birfy deleted the fix/2637-track-tasks-name-normalize branch November 7, 2026 20:57
@github-actions github-actions Bot removed the agent-pr Pull request opened by an agent label Nov 7, 2026
@Birfy Birfy added agent-pr Pull request opened by an agent and removed agent-pr Pull request opened by an agent labels Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

1 participant