fix(session): trust authoritative projection frames

This commit is contained in:
pku-xht
2026-08-25 23:18:46 +08:00
parent 5fe7dc333f
commit cdba045dfc
14 changed files with 53 additions and 44 deletions
@@ -70,12 +70,12 @@ interface Channel {
* One session's projection values. A list hint can fill or advance only a
* tentative row. A complete baseline replaces or clears every tentative row,
* regardless of its claimed sequence, while preserving authoritative frames
* newer than the baseline cut. Frames use higher-sequence-wins after promoting
* an equal-sequence hint to authoritative state. A key the store has never seen
* reads `undefined` (capability absent). Faces are identity-stable per key
* (create-on-demand, cached) so the React side binds each exactly once; the
* store-level channel (`subscribeAny`) serves coarse consumers (the manager's
* list projection reads the `title` key).
* newer than the baseline cut. The first authoritative frame replaces any
* tentative hint; later authoritative frames use higher-sequence-wins. A key
* the store has never seen reads `undefined` (capability absent). Faces are
* identity-stable per key (create-on-demand, cached) so the React side binds
* each exactly once; the store-level channel (`subscribeAny`) serves coarse
* consumers (the manager's list projection reads the `title` key).
*/
export class ProjectionValueStore {
private readonly rows = new Map<string, Row>()
@@ -152,7 +152,7 @@ export class ProjectionValueStore {
*/
apply(key: string, value: unknown, seq: number): void {
const row = this.rows.get(key)
if (row !== undefined && (seq < row.seq || (seq === row.seq && row.provenance === 'authoritative'))) return
if (row?.provenance === 'authoritative' && seq <= row.seq) return
this.rows.set(key, { value, seq, provenance: 'authoritative' })
this.changed(key)
}
@@ -157,11 +157,13 @@ describe('Session tail-page seeding', () => {
expect(session.projections.get('test/marks')).toEqual({ marks: ['authoritative'] })
})
it('preserves an authoritative frame that lands while opening waits for its older baseline', async () => {
it('preserves an authoritative frame below a higher hint while opening waits for its older baseline', async () => {
const api = new FakeApiClient()
const history = deferred<Awaited<ReturnType<FakeApiClient['onHistory']>>>()
api.onHistory = () => history.promise
const session = new Session(SID, api, fakeRemote(api))
const projections = new ProjectionValueStore()
projections.prewarm('test/marks', { marks: ['hint-9'] }, 9)
const session = new Session(SID, api, fakeRemote(api), { projections })
const opening = session.open()
session.projections.apply('test/marks', { marks: ['live-3'] }, 3)