Skip to content

fix(host): write a meeting's state before the meeting tool answers - #1781

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/3-meeting-persist
Oct 30, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/3-meeting-persist

Conversation

@HugoXK

@HugoXK HugoXK commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1774

What

A meeting is a record on disk, not a decoration of the live process. Every write of the meeting tool now reaches the team file before the tool answers: open, position, block and resume save once the record is written, and decide saves twice — once with the produced card ids, before the decision file is written, and once with closed. core/src/host/meetings.js used save nowhere; the only save on that path was task-create's own (tasks.js:287), whose snapshot is taken before the decision is archived, so the disk kept deliberating forever.

Docs-not-needed: docs/subsystems/core-host.md already describes a meeting as a record in the existing store (state.meetings); this change only makes that true at rest, and #1751 edits the same page, so the user-facing guarantee is in changelog.d/1774-meetings-persist.fixed.md.

Tip

  • head 55230ea129c8cc8ba994b9e23b28c80564675b71
  • tree a79d6bf7ae46c041ee57c1b7d71166d2eb055f47
  • base 92a4cf262cb8f2469f800f12e5cfe006abb4d538 (live main at fetch time)
  • 5 files, +231/−16: core/src/host/meetings.js +28/−8, core/test/meetings-persist.test.js +87 (new), changelog.d/1774-meetings-persist.fixed.md +1, and the two generated mirrors patches/ds-bot/files/src/host/meetings.js +28/−8 and patches/ds-bot/files/test/meetings-persist.test.js +87 (new). Every byte under patches/ds-bot/ is written by node scripts/ds-bot-patches.mjs generate; no hand-edited hunk. On this base 0002-flybot-api-host.patch does not change at all (measured: blob 789c50d3… before and after), the change rides the whole-file mirror.

Red first

On live main (92a4cf26) with core/src/host/meetings.js restored to the base bytes, node --import ./test/harness-resolve.mjs --test test/meetings-persist.test.js:

not ok 1 - P-209: a decided meeting survives a restart, and a second decide is refused with closed
  error: 'a restart must not forget the decision, got: meeting-3e1a469135 [deliberating] Which storage shape should Stage 4 use?'
not ok 2 - P-209: an open meeting and a recorded position survive a restart
  error: 'not-found: no meeting meeting-4de66233e6'

Those two are the two halves of the defect: the decided meeting reads back [deliberating] after a restart, and an open meeting is gone entirely. On the base, a second decide after a restart succeeds — the card count goes 1 → 2 and decisions/ gains a second …-2.md; the fixed tree refuses it with closed and leaves both counts unchanged (asserted).

With the fix in place: the two new tests 2/2, and meetings.test.js + meetings-decide-paths.test.js + meetings-persist.test.js 29/29 (the existing 27 do not regress, including #1765's red-first tests).

Gates at this head

enqueue-guard at this tip is expected to refuse until a Verifier report names 55230ea129c8; the exact text is quoted after the first CI run on the head (fork: the issue-reference and agent-pr rules are not asked of it).

What I ran, at 55230ea129c8:

  • npm --prefix core run build then node scripts/ds-bot-patches.mjs generate, then a second generate (only 0014's 2/2 pure hunk-header drift; restored to base bytes)
  • two node scripts/ds-bot-patches.mjs check passes, three lines identical and green each:
    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=92a4cf262cb8 npm run verify — exit 0: core 2135, social 539, tree 125, timeline 129, workflow 289, .github 549, interop 37, live-e2e 24, 0 failures; arch-docs: OK (5 changed file(s)); build-client --check clean; lint 70 warnings, 0 errors
  • node .github/scripts/changelog.mjs check — 10 fragments well formed

Not run: the smoke bench, the CI package job, and any push other than this branch.

maintainer_can_modify: true.

Checkpoint

Written-by: Reviewer

{
  "pr": 1781,
  "claim": "Dev",
  "issue": 1774,
  "summary": "The host meeting tool now writes a meeting to the team file before the tool answers. open, position, block and resume save once the record is written, and decide saves twice — first with the produced card ids while the meeting is still deliberating, then with closed after the decision file is archived. Before this the meeting store never called save on that path, so a decided meeting read back as deliberating after a restart and an open meeting vanished entirely. A second decide after a restart also wrote a second card and a second decision file instead of being refused with closed.",
  "files": [
    "core/src/host/meetings.js",
    "core/test/meetings-persist.test.js",
    "changelog.d/1774-meetings-persist.fixed.md"
  ],
  "checks": {
    "ran": "cd core && TZ=UTC node --import ./test/harness-resolve.mjs --test test/meetings.test.js test/meetings-decide-paths.test.js test/meetings-persist.test.js",
    "result": "green",
    "at": "55230ea129c8cc8ba994b9e23b28c80564675b71"
  },
  "next": "none — ready for review"
}

@HugoXK

HugoXK commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

Review request for this tip: 55230ea129c8cc8ba994b9e23b28c80564675b71 needs a Verifier verdict naming it. At this head tests-ok is green, merge-gate passes, mergeable_state is only held by the missing verdict; enqueue-guard refuses for exactly one reason — no Verifier report names the tip 55230ea129c8. 5 files +231/−16 (5 real files: core/src/host/meetings.js +28/−8, new core/test/meetings-persist.test.js +87, changelog +1, two regenerated mirrors), base 92a4cf26, maintainer_can_modify: true, not a draft. Fixes #1774.

…owLab#1774)

Every write of the `meeting` tool now reaches the team file before the tool
answers: `open`, `position`, `block` and `resume` save once the record is
written, and `decide` saves twice - once with the produced card ids before the
decision file is written, and once with `closed` - so a restart reads the state
the caller was told, and a stale retry is refused with `closed` instead of
doubling the card and the `decisions/` file.

Docs-not-needed: docs/subsystems/core-host.md already describes a meeting as a record in the existing store (`state.meetings`); this change only makes that true at rest, and ThinkFlowLab#1751 edits the same page, so the user-facing guarantee is in changelog.d/1774-meetings-persist.fixed.md.
@Birfy

Birfy commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator

Verdict: PASS at 55230ea
Written-by: Reviewer
Attestation: 55230ea role=Reviewer

Ran at this tip:

$ cd core && TZ=UTC node --import ./test/harness-resolve.mjs --test test/meetings.test.js test/meetings-decide-paths.test.js test/meetings-persist.test.js
# tests 29  # pass 29  # fail 0
$ cp <base 92a4cf26>/core/src/host/meetings.js core/src/host/meetings.js && cd core && TZ=UTC node --import ./test/harness-resolve.mjs --test test/meetings-persist.test.js
# tests 2  # pass 0  # fail 2

Red first holds. With core/src/host/meetings.js restored to the base blob at 92a4cf26, both new P-209 tests fail — the decided meeting reads back [deliberating], the open meeting reads back not-found — and with the tip file they pass. The 27 existing tests in meetings.test.js + meetings-decide-paths.test.js do not regress (29/29 at the tip).

What the change does, read at the tip: open, position, block and resume each call await rt.save() before summary() answers, and decide saves twice — once with the produced card ids while the record is still deliberating, once with closed after the decision file is archived (core/src/host/meetings.js:311, :351, :416, :421, :428, :433). The ordering is the one the defect needs: the ids reach disk before the next card is written, and the decision is on disk before decide answers, so a stale reader's retry is refused with closed instead of writing a second decisions/…-2.md and a second card.

Scope, 92a4cf26...55230ea1 (ahead 1, behind 0, base is live main): 5 files — core/src/host/meetings.js +28/−8, new core/test/meetings-persist.test.js +87, changelog.d/1774-meetings-persist.fixed.md +1, and the two generated mirrors. Both patches/ds-bot/files/… mirrors are byte-identical to their core/ sources (cmp clean), so nothing hand-edited rode in under patches/.

Check-runs at this tip: tests-ok, merge-gate, package, Node 24 · DSH 0.2.0-rc.2, plugins (tree|social|timeline|workflow), judge, reviewed tip, risk tier, agent-audience all green. The only red is enqueue-guard, and its reason is exactly the missing conclusion this report supplies: no Verifier report names the tip 55230ea129c8.

Docs-not-needed: is in the body; the fragment names #1774 and states the user-facing guarantee. Not run: the full npm run verify (CI's tests-ok covers it green at this tip), the smoke bench, and the package job.

@github-actions github-actions Bot added the pass 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 8489264 Oct 30, 2026
14 checks passed
@Birfy
Birfy deleted the dev/3-meeting-persist branch October 30, 2026 05:54
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.

meetings: a decision is never written to disk, so a restart forgets it and a second decide doubles the card and the file

2 participants