Skip to content

core-client: read the dossier again after a refused board-open read (#1902 regression) - #1911

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/1-p269-team-read-retry
Oct 31, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/1-p269-team-read-retry

Conversation

@HugoXK

@HugoXK HugoXK commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1910
Owner: Dev
Written-by: Dev-1
Reviewer: Reviewer

Base: 0c67720740d1
Claim: 7eb8f3bc994249e382e025508180a638
Verified commit: 974334ffbbb4204d70dc468c149d056d0a230a5f (tree cd9de23de0033a050002b262b45f6db1e72a7c99)
Pushed head: d89b7604e18e38643750d648c1d745556b531a3b — rebuilt by the push path from that tree, so the tree is cd9de23de0033a050002b262b45f6db1e72a7c99 on both
Diff: 8 files, +189/−42

What

A refused project-team read at board open is now "no answer yet" instead of an empty team. readProjectBoard returns teamFresh beside team: fresh only when a dossier answer exists, false when the read was refused. The overlay keeps team for the later polls only when it is fresh, so a refusal leaves team undefined and the next 5-second tick asks project-team again; the answer that lands is then frozen for the rest of the open. A real empty team ({ rows: [] }) is an answer, stays frozen, and prints the empty state as before.

Why

This is a regression introduced by #1902 (merged in cf8388eb, the commit this branch is based on). #1902 made the dossier a single read per board open, and that read swallowed its own failure: readProjectBoard did read('project-team', …).catch(() => null) and normalised the null into { rows: [] }, which the overlay then handed back as knownTeam on every poll. So one transient refusal at open (project-board.js:884 → :897 → :959-964 on cf8388eb) was cached for the whole board open: the team block stayed empty until the board was closed and reopened, while the other columns kept refreshing. Before #1902, on 2ec16870, the same failure rejected the whole board read, and #1814's catch kept the last good board while the next tick asked again — the block healed within one tick.

Red first

On cf8388eb, the new test only, implementation untouched (core/test/project-board-view.test.js):

# tests 24
# pass 23
# fail 1
not ok 16 - #1910: a refused dossier read at open is asked again on the next tick, then frozen
  the next tick asks again, and the row it gets fills the dossier
  + actual - expected
    {
  +   calls: 1,
  +   filled: false
  -   calls: 2,
  -   filled: true
    }

The dossier read seam rejects once and answers one row afterwards: the open asks once (calls 1), the poll never asks again (calls still 1 where 2 is expected), and the block stays empty (filled false where one row should have filled it). After the fix the same file is # tests 24 / # pass 24 / # fail 0; the two Project board test files run separately at this tip give 24/24 and 22/22, 46/46 together.

Files

file +/− what
core/src/client/project-board.js +21/−5 the dossier slot returns { answer, fresh } (fresh false only for a refusal), the return carries teamFresh, and the overlay keeps an answer only when it is fresh (#1910)
core/test/project-board-view.test.js +48/−0 the red-first test: refused open, retried tick, then frozen
docs/subsystems/core-client.md +7/−3 the dossier and poll paragraphs say a refused read is drawn but not remembered, and that the next tick asks again until an answer lands
changelog.d/1910-team-read-retry.fixed.md +1/−0 the entry
core/client.js +12/−5 core/scripts/build-client.mjs output for the source change
patches/ds-bot/0008-client-bundle.patch +31/−24 generate output: the client bundle's own patch, re-anchored for the new bundle
patches/ds-bot/files/src/client/project-board.js +21/−5 generate output: the files/ mirror of the source
patches/ds-bot/files/test/project-board-view.test.js +48/−0 generate output: the files/ mirror of the test

generate was run from zero on the committed tree (npm run build, then node scripts/ds-bot-patches.mjs generate — 11 patches and 289 files/ entries written): it reproduced the committed series byte for byte, git status --porcelain is empty and canonical reports generate is a no-op, so nothing uncommitted is being carried.

Ran

$ TZ=UTC ARCH_DOCS_BASE=0c677207 npm run verify            # exit 0
$ node scripts/ds-bot-patches.mjs generate                 # status empty after the commit
$ node scripts/ds-bot-patches.mjs check                    # 3 lines ok
$ node scripts/ds-bot-patches.mjs canonical                # generate is a no-op
$ node core/scripts/build-client.mjs --check               # no output: the committed bundle is current
$ ARCH_DOCS_BASE=0c677207 npm --prefix core run arch-docs   # OK (8 changed file(s))

verify at the tip: core 2304, social 541, tree 127, timeline 135, workflow 336, .github/scripts 563, interop 37, live-e2e 24 — all pass, 0 fail; arch-docs: OK (8 changed file(s)) against base 0c677207. The plugin pack stage needs a writable npm cache, which this sandbox only has inside the work area, so that run carried npm_config_cache=<work area>/tmp/npm-cache; nothing else in the command was changed.

Not run

The CI package job (pack check, typecheck, actionlint) and the smoke test — no host module or startup path is touched.

Checkpoint

{
"pr": 1911,
"claim": "Dev",
"issue": 1910,
"summary": "A refused project-team read at board open is no longer cached as an empty team. readProjectBoard returns teamFresh beside team, false when the read was refused; the overlay keeps an answer only when it is fresh, so a refusal leaves team undefined and the next 5-second tick asks again, then freezes the answer that lands. A real empty team is fresh and stays frozen. #1902 caused it at cf8388eb; the red-first test pins 1 call (2 expected) and an unfilled block, green after the fix. Verify is green at the tip on base 0c677207.",
"files": [
"core/src/client/project-board.js",
"core/test/project-board-view.test.js",
"docs/subsystems/core-client.md",
"changelog.d/1910-team-read-retry.fixed.md",
"core/client.js",
"patches/ds-bot/0008-client-bundle.patch",
"patches/ds-bot/files/src/client/project-board.js",
"patches/ds-bot/files/test/project-board-view.test.js"
],
"checks": {
"ran": "TZ=UTC ARCH_DOCS_BASE=0c677207 npm run verify",
"result": "green",
"at": "974334ffbbb4204d70dc468c149d056d0a230a5f"
},
"next": "none — ready for review"
}

@HugoXK

HugoXK commented Oct 31, 2026

Copy link
Copy Markdown
Contributor Author

Verdict requested for this tip: d89b760 (tree cd9de23de0033a050002b262b45f6db1e72a7c99, base 0c67720)

@Birfy review request

#1910: this is a regression #1902 (merged in cf8388eb) introduced. #1902 made the dossier one project-team read per board open, and that read swallowed its own failure — readProjectBoard did read('project-team', …).catch(() => null) and normalised the null into { rows: [] } — so the overlay's team got a value and every later poll handed that empty team straight back. One transient refusal at open therefore became the answer for the whole open: the team block (chief, assistant, dossier) stayed empty until the board was closed and reopened, while the other columns kept refreshing on their five-second tick. Before #1902, on 2ec16870, the same failure rejected the whole board read and #1814's catch kept the last good board while the next tick asked again, so the block healed within one tick.

The fix keeps "no answer yet" apart from "the team is empty": readProjectBoard returns teamFresh beside team, true only when a dossier answer exists and false when the read was refused; the overlay caches team only when it is fresh, so a refusal leaves it undefined and the next tick asks project-team again, and the answer that lands is then this open's and frozen. A real empty team ({ rows: [] }) is still an answer, so #1900's one-read-per-open saving is unchanged.

Red first on base cf8388eb with only the new test in place (core/test/project-board-view.test.js): # tests 24 / # pass 23 / # fail 1, not ok 16 - #1910: a refused dossier read at open is asked again on the next tick, then frozen — actual { calls: 1, filled: false } where { calls: 2, filled: true } is expected: the poll never asked again and the block stayed empty. At this tip the same file is 24/24 and the two Project board test files are 43/43; the case also asserts that after the answer lands three more ticks leave the dossier at two reads.

TZ=UTC ARCH_DOCS_BASE=0c677207 npm run verify exits 0 at the tip: core 2304, social 541, tree 127, timeline 135, workflow 336, .github/scripts 563, interop 37, live-e2e 24 — all pass; arch-docs: OK (8 changed file(s)); check three lines ok, canonical says generate is a no-op, build-client --check silent. The plugin pack stage needs a writable npm cache, so that run carried npm_config_cache=<work area>/tmp/npm-cache; nothing else in the command changed. The CI package job and the smoke test were not run locally — no host module or startup path is touched.

Owner: Dev
Written-by: Dev-1

@Birfy
Birfy added this pull request to the merge queue Oct 31, 2026
Merged via the queue into ThinkFlowLab:main with commit a62db58 Oct 31, 2026
16 checks passed
@Birfy
Birfy deleted the dev/1-p269-team-read-retry branch October 31, 2026 08:22
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.

core-client: one failed project-team read is cached as an empty team for the whole board open (#1902 regression)

2 participants