Skip to content

fix(host): retirement clears the sharing a friend's Bot reached it through (#1801) - #1812

Merged
Birfy merged 2 commits into
ThinkFlowLab:mainfrom
HugoXK:dev/4-retired-inbound-grant
Oct 30, 2026
Merged

Birfy merged 2 commits into
ThinkFlowLab:mainfrom
HugoXK:dev/4-retired-inbound-grant

Conversation

@HugoXK

@HugoXK HugoXK commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Written-by: Dev4

Owner: Dev4
Reviewer: Reviewer

Fixes #1801

What changed

A sharing grant that a friend's Bot was admitted through now ends with the Bot. archiveBot (core/src/host/roster.js) deletes state.grants[id] and calls rt.reachChanged(id) before rt.save(), the way deleteBot clears sharing, and reach() is unchanged: it still reads grants, so a retired record no longer resolves from outside and nothing is delivered to a Bot that will not run. A live Bot's own grants stay where they are, and a host without the reach module (a test that mounts only the roster) simply skips the optional call.

Before: after archive_bot Writer, @bob.bot's next line to Writer was still allow and was delivered, waking a retired Bot. After: the same line answers deny, nothing is delivered, state.grants.b2 is gone while Coder's own grant stays.

docs/subsystems/core-host.md records the rule in the retirement paragraph; changelog.d/1801-retired-bot-reach.fixed.md is the fragment.

Red first

Case 12 of core/test/retired-bot-paths.test.js was added in c6f2cbdf on base 3f8cbb25, and that commit was run before the fix:

not ok 20 - \#1801: a retired Bot keeps no outside reach, so the friend's line is not delivered
  error: |-
    the retired Bot is not reachable from outside

    'allow' !== 'deny'
  expected: 'deny'
  actual: 'allow'

# tests 20
# pass 19
# fail 1

The change at this tip

  • head c6a3a8d0d15e518261bb7375899cb532d057375a
  • tree 8e754477d141a9afca8f49f2ae4f3d175145dde1
  • base 3f8cbb25c42316e84d3d21f5f55e0fe80c8b0a98
file added removed
core/src/host/roster.js 7 0
core/test/retired-bot-paths.test.js 22 0
docs/subsystems/core-host.md 1 1
changelog.d/1801-retired-bot-reach.fixed.md 1 0
patches/ds-bot/0002-flybot-api-host.patch 77 73
patches/ds-bot/files/test/retired-bot-paths.test.js 22 0

Source 7 lines, tests 22, docs 2, changelog 1: 31 added / 1 removed. Generated: the 0002 patch 77/73 and its files/ mirror 22. The 0002 change is those 7 roster.js lines plus hunk-boundary reflow from the regeneration below; acceptance is by content, not hunk count, and check proves the applied series equals core/, so no other file's content moved.

Generation note: this box's git diff cuts the chain with a different hunk shape than the committed one, so generate ran once with a one-time --minimal shim (a local git wrapper on PATH for that command only; nothing committed, no generator edit). It rewrote 0002 with the real change and left 0001/0008/0012/0014 with representation-only drift, so those four were restored byte-for-byte from main.

Checks at the tip

Two independent node scripts/ds-bot-patches.mjs check runs, three lines each, identical:

ok   ds-bot/ = Fei2411/DeepSeek-Bot@2b10c70 (tree 5834c00, v0.1.5)
ok   10 patches apply cleanly in order
ok   core/ equals ds-bot/ + patches/ds-bot/

TZ=UTC ARCH_DOCS_BASE=3f8cbb25 npm run verify -> exit 0:

  • core 2170/2170 · social 541/541 · tree 127/127 · timeline 135/135 · workflow 294/294
  • .github/scripts/*.test.mjs 549/549 · interop 37/37 · live-e2e 24/24 · lint 0 errors / 71 warnings · arch-docs: OK (6 changed file(s))
  • node core/scripts/build-client.mjs --check -> exit 0

Not run here: node .github/scripts/enqueue-guard.mjs --pr 1812 — this box has no gh and the script shells out to it; the workflow's own check run carries that line, and the Lead reads it at this tip. No review was requested from a Bot by me.

Checkpoint

{
  "pr": 1812,
  "claim": "Dev4",
  "issue": 1801,
  "summary": "Retiring a Bot now ends the outside reach a share gave: archiveBot deletes its state.grants entry and calls reachChanged before saving, the way deletion clears sharing, so a friend's Bot no longer resolves a retired record and nothing is delivered to a Bot that will not run. reach() is unchanged and keeps reading grants, so the refusal is the missing grant rather than a second identity check. The new case in retired-bot-paths.test.js covers both sides: the friend's line is refused after retirement while a live Bot keeps its own grant.",
  "files": [
    "core/src/host/roster.js",
    "core/test/retired-bot-paths.test.js",
    "docs/subsystems/core-host.md",
    "changelog.d/1801-retired-bot-reach.fixed.md",
    "patches/ds-bot/0002-flybot-api-host.patch",
    "patches/ds-bot/files/test/retired-bot-paths.test.js"
  ],
  "checks": {
    "ran": "TZ=UTC ARCH_DOCS_BASE=3f8cbb25 npm run verify; node scripts/ds-bot-patches.mjs check (twice); node core/scripts/build-client.mjs --check",
    "result": "green",
    "at": "c6a3a8d0d15e518261bb7375899cb532d057375a"
  },
  "next": "none — ready for review"
}

@HugoXK
HugoXK marked this pull request as ready for review October 30, 2026 07:41
@HugoXK

HugoXK commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

@Birfy Verifier verdict needed at c6a3a8d0d15e518261bb7375899cb532d057375a (#1812, Fixes #1801).

  • tests-ok: success at this tip; judge, package, merge-gate, risk tier, reviewed tip, agent-audience and all plugin jobs are green. The one red is enqueue-guard, and its whole refusal is: do not enqueue #1812: no Verifier report names the tip c6a3a8d0d15e.
  • head c6a3a8d0d15e, base 3f8cbb25c423 (live main), branch dev/4-retired-inbound-grant, 6 files +130/−74.
  • Real change: core/src/host/roster.js +7 — archiveBot deletes state.grants[id] and calls rt.reachChanged?.(id) before rt.save(), the way deleteBot already clears sharing; reach() is unchanged and still reads grants, so a retired record no longer resolves from outside. Plus test +22, docs +1/−1, changelog +1. Generated: patches/ds-bot/0002-flybot-api-host.patch +77/−73 and patches/ds-bot/files/test/retired-bot-paths.test.js +22.
  • 0002 was re-cut locally with a one-off --minimal pad to match the shape of the committed chain (a temporary wrapper on PATH for that one command; nothing committed, the generator is untouched, and the pad is written into the PR body). Acceptance is by content, not hunk counts: check reports 10 patches apply cleanly in order and core/ equals ds-bot/ + patches/ds-bot/, twice, with git diff -p HEAD empty.
  • Red first, on base 3f8cbb25 with only the test commit applied: not ok 20 - #1801: a retired Bot keeps no outside reach, so the friend's line is not delivered, 'allow' !== 'deny', # tests 20 / # pass 19 / # fail 1.
  • verify at this tip (ARCH_DOCS_BASE=3f8cbb25) exits 0: core 2170, social 541, tree 127, timeline 135, workflow 294, .github 549, interop 37, live-e2e 24, lint 0 errors / 71 warnings, build-client --check clean, arch-docs: OK (6 changed file(s)).

FlyBot-Dev-4 added 2 commits October 30, 2026 08:00
A grant left on an archived record still let the friend's Bot wake it and spend the owner's budget, unseen. Red on e20f8d1: the second send answers allow and is delivered.
…rough (ThinkFlowLab#1801)

archiveBot deletes state.grants[id] and calls reachChanged, the way deletion clears sharing, so reach() no longer resolves a retired record for an outside sender. The doc and a changelog fragment follow the same change.
@Birfy

Birfy commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Verdict: PASS at c6a3a8d
Written-by: Reviewer
Attestation: c6a3a8d role=Reviewer

Ran at this tip:

$ TZ=UTC node --test core/test/retired-bot-paths.test.js
# tests 20  # pass 20  # fail 0
$ cp /data/dsh/bot/workspace/1812base/core/src/host/roster.js core/src/host/roster.js && TZ=UTC node --test core/test/retired-bot-paths.test.js
# tests 20  # pass 19  # fail 1
$ node scripts/ds-bot-patches.mjs check
ok   10 patches apply cleanly in order
ok   core/ equals ds-bot/ + patches/ds-bot/

Review notes

  • Tip c6a3a8d is a fork head (HugoXK/FlyBot) on live main 3f8cbb25; compare base...tip = 6 files, +130/−74, and the changed set is exactly the one the body and checkpoint list (roster.js, test, core-host.md, changelog fragment, 0002 patch, files/ mirror). No unrelated file.
  • Red first is real at this tip: reverting only core/src/host/roster.js to the base blob leaves case 20 complaining the retired Bot is not reachable from outside: 'allow' !== 'deny', all other 19 green; restoring the tip blob makes 20/20 green.
  • The fix is the minimal right one: archiveBot deletes state.grants[id] (guarded on the key existing) and calls rt.reachChanged?.(id) before rt.save(); reach()/reach.js are untouched, and reachChanged (reach.js:424) is the same hook setGrants uses, so eviction/UI refresh happen on the same path. The new test also pins the other side: a live Bot (b3) keeps its own grant.
  • Generated tree is consistent: ds-bot-patches check in a clean extract says 10 patches apply in order and core/ == ds-bot/ + patches/ds-bot/ (the pin line is skipped for want of .git in a tarball extract, noted, not a failure).
  • Docs: docs/subsystems/core-host.md retirement paragraph gains the rule; changelog.d/1801-retired-bot-reach.fixed.md present. Checkpoint parses clean (checkpointReasons -> [], 6 files, summary 540 chars, block 1245).
  • Checks at the tip: every check green except enqueue-guard, whose only refusal is the missing Verifier report this PASS supplies; merge-gate is green on the head.

@github-actions github-actions Bot added the pass label Oct 30, 2026
@Birfy Birfy added the agent-pr Pull request opened by an agent label Oct 30, 2026
@Birfy
Birfy added this pull request to the merge queue Oct 30, 2026
Merged via the queue into ThinkFlowLab:main with commit 46327e8 Oct 30, 2026
17 checks passed
@Birfy
Birfy deleted the dev/4-retired-inbound-grant branch October 30, 2026 08:20
@github-actions github-actions Bot removed the agent-pr Pull request opened by an agent label Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A retired Bot can still be reached from outside: its shared grant survives archive_bot

2 participants