fix(contract): the flush gate's internals are #-private — they are not doors
The 10.4.11 flush single-flight work added `startFlushLeader` and `promoteQueuedFlush` as TypeScript `private` methods. `private` is erased at compile time, so both still land on the prototype — and the contract manifest emitter reads the surface the BUILD exposes, skipping only names that start with an underscore. On the next regeneration both would have been emitted as contract doors, obliging every engine implementing contract 1 to provide the flush gate's own bookkeeping. A door is a promise; these are internals. Converted to ECMAScript-private (`#`), which keeps them off the prototype entirely, and the reason is recorded on both so the next internal is not written as `private` by habit. `_runFlush` — the flush body itself — was already safe by the emitter's underscore rule. Verified: `npm run build && node scripts/emit-contract-manifest.mjs` then `--check` green at 302 doors, with neither name present. TWO MANIFEST NOTES, both deliberate and neither hidden: 1. The regenerated manifest gains `MetadataArrayTooLargeError`. The emitter lists every `*Error` export from brainyError.js, and that class is the write door's refusal for an over-bound metadata array (this branch's array-bound commit). It is a real addition to the engine's error surface, so the manifest is right to carry it — flagged here because it is a contract-surface change that the cut should accept knowingly, not a side effect that slipped in. 2. `armIdleFlushTimer` and `kickBackgroundFlush` are TypeScript `private` in src and ARE already in the committed manifest as doors — the same leak, one release older. They are left exactly as they are: removing a name the manifest already publishes is a contract deletion, not a hygiene fix, and it belongs to whoever owns contract 1 rather than to this branch.
This commit is contained in:
parent
f27a777615
commit
72c8ee6acd
2 changed files with 18 additions and 7 deletions
|
|
@ -1507,6 +1507,7 @@
|
||||||
"BrainyError",
|
"BrainyError",
|
||||||
"DerivedArtifactMissingError",
|
"DerivedArtifactMissingError",
|
||||||
"GraphIndexNotReadyError",
|
"GraphIndexNotReadyError",
|
||||||
|
"MetadataArrayTooLargeError",
|
||||||
"MetadataIndexNotReadyError",
|
"MetadataIndexNotReadyError",
|
||||||
"MigrationInProgressError",
|
"MigrationInProgressError",
|
||||||
"ProtectedArtifactError",
|
"ProtectedArtifactError",
|
||||||
|
|
|
||||||
|
|
@ -13342,25 +13342,33 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
||||||
}
|
}
|
||||||
return this._flushQueued
|
return this._flushQueued
|
||||||
}
|
}
|
||||||
return this.startFlushLeader()
|
return this.#startFlushLeader()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Run one flush body as the leader and install it as
|
* @description Run one flush body as the leader and install it as
|
||||||
* `_flushInFlight`. On settle — resolved OR rejected — the gate opens and
|
* `_flushInFlight`.
|
||||||
|
*
|
||||||
|
* ECMAScript-private (`#`), not TypeScript `private`: `private` is erased at
|
||||||
|
* compile time, so the method still lands on the prototype and the contract
|
||||||
|
* manifest — which reads the surface the BUILD exposes — emitted it as a
|
||||||
|
* door. A door is a promise every engine implementing the contract must
|
||||||
|
* keep, and this is the flush gate's own bookkeeping, not a promise. `#`
|
||||||
|
* keeps it off the prototype, so the emitter cannot see it.
|
||||||
|
* On settle — resolved OR rejected — the gate opens and
|
||||||
* the ONE queued waiter (if any) is promoted. The `finally` callback returns
|
* the ONE queued waiter (if any) is promoted. The `finally` callback returns
|
||||||
* nothing on purpose: a callback that returned the promoted run's promise
|
* nothing on purpose: a callback that returned the promoted run's promise
|
||||||
* would make the leader await its own follower.
|
* would make the leader await its own follower.
|
||||||
* @returns The leader's own promise, settling on its own body alone.
|
* @returns The leader's own promise, settling on its own body alone.
|
||||||
*/
|
*/
|
||||||
private startFlushLeader(): Promise<void> {
|
#startFlushLeader(): Promise<void> {
|
||||||
const run = this._runFlush()
|
const run = this._runFlush()
|
||||||
// `finally` and not `then`: a failed flush must still open the gate, or
|
// `finally` and not `then`: a failed flush must still open the gate, or
|
||||||
// one rejection would wedge every later flush behind a promise nobody
|
// one rejection would wedge every later flush behind a promise nobody
|
||||||
// will ever settle.
|
// will ever settle.
|
||||||
const gated: Promise<void> = run.finally(() => {
|
const gated: Promise<void> = run.finally(() => {
|
||||||
if (this._flushInFlight === gated) this._flushInFlight = null
|
if (this._flushInFlight === gated) this._flushInFlight = null
|
||||||
this.promoteQueuedFlush()
|
this.#promoteQueuedFlush()
|
||||||
})
|
})
|
||||||
this._flushInFlight = gated
|
this._flushInFlight = gated
|
||||||
return gated
|
return gated
|
||||||
|
|
@ -13368,12 +13376,14 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Promote the single queued waiter (if one is waiting) to
|
* @description Promote the single queued waiter (if one is waiting) to
|
||||||
* leader and settle its deferred from that run. Never throws into the
|
* leader and settle its deferred from that run. ECMAScript-private for the
|
||||||
|
* same reason as {@link flush}'s leader starter: internals are not doors.
|
||||||
|
* Never throws into the
|
||||||
* leader's `finally`: a synchronous failure starting the promoted run is
|
* leader's `finally`: a synchronous failure starting the promoted run is
|
||||||
* reported to the waiter, which must be settled on every path.
|
* reported to the waiter, which must be settled on every path.
|
||||||
* @returns Nothing.
|
* @returns Nothing.
|
||||||
*/
|
*/
|
||||||
private promoteQueuedFlush(): void {
|
#promoteQueuedFlush(): void {
|
||||||
const settle = this._flushQueuedSettle
|
const settle = this._flushQueuedSettle
|
||||||
if (!settle) return
|
if (!settle) return
|
||||||
// Clear BEFORE starting, so the promoted run's own joiners queue afresh
|
// Clear BEFORE starting, so the promoted run's own joiners queue afresh
|
||||||
|
|
@ -13381,7 +13391,7 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
||||||
this._flushQueued = null
|
this._flushQueued = null
|
||||||
this._flushQueuedSettle = null
|
this._flushQueuedSettle = null
|
||||||
try {
|
try {
|
||||||
this.startFlushLeader().then(settle.resolve, settle.reject)
|
this.#startFlushLeader().then(settle.resolve, settle.reject)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
settle.reject(error)
|
settle.reject(error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Reference in a new issue