Ignore:
Timestamp:
08/07/2026 07:16:27 PM (5 weeks ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
a66266d
Parents:
01fb44f
git-author:
Robin <roboburr@…> (08/07/2026 07:16:25 PM)
git-committer:
roboburr <roboburr@…> (08/07/2026 07:16:27 PM)
Message:

De gate-stand komt uit de besluiten, want er zijn geen lokale accounts

Barts correctie, en hij raakt twee dingen die ik fout had.

ER ZIJN GEEN LOKALE ACCOUNTS. wardGateSetting() leest de kolom alleen als de ward
op onze eigen base staat, en met een Klonkt per gebruiker woont elke ward elders.
Die functie gaf dus voor IEDERE ward null, en het gate-paneel toonde overal
"onbekend". Ik noemde dat een randgeval terwijl het het enige geval is.

EN DE GUARDIAN WEET HET WEL: hij kreeg de uitslag van het besluit door.
ap_gated_sent bewaart per voorstel de feature, de waarde en de uitkomst, dus een
geaccepteerd voorstel met waarde true IS de stand. knownSetting() leest dat.

Drie standen in plaats van twee. "Uit" en "voor zover wij weten uit" zijn niet
hetzelfde: dat tweede betekent dat niemand er ooit over besloot, en dat hoort
niet te lezen als een genomen besluit. De rij draagt nu decided en het scherm
zegt "uit (nog niets over besloten)".

Daarmee vervalt ook het gat dat ik een commit eerder noteerde: de richting van de
voorstelknop volgt nu een BEKENDE stand, dus voor een ward elders kun je ook
DICHTZETTEN voorstellen. Dat was precies de veilige richting die ontbrak.

De trap blokkeert alleen op een BESLOTEN dicht, niet op de standaard. Anders kan
afspelen nooit als eerste voorgesteld worden, en zo ging er ooit een hele
voorstelronde de verkeerde gate in.

BEKEND GAT, in het commentaar bij knownSetting gezet en niet hier opgelost: dit
ziet alleen onze EIGEN voorstellen. Antwoordde je op dat van een mede-guardian,
dan komt de uitslag wel binnen (gated_outcome) maar wordt hij niet bewaard --
handshake.js legt alleen vast voor sent-rijen die van ons zijn. Een gate die een
ander heeft geopend leest hier dus als uit, en dat is de onveilige kant.

4 tests erbij, waaronder de terugval op de oude kale-boolean vorm. Suite 599/599.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/guardianship/gated.js

    r01fb44f r72d8eff  
    9797export function gateRows({ settings = {}, guardianCount = null, proposals = [], waiting = {} } = {}) {
    9898  return GATE_CATALOGUE.map((g) => {
    99     const value = Object.prototype.hasOwnProperty.call(settings, g.feature) ? settings[g.feature] : null;
     99    // Een stand kan drie dingen zijn: beslist-aan, beslist-uit, of de standaard
     100    // omdat er nooit iets besloten is. Dat derde als "uit" tonen zou een besluit
     101    // suggereren dat niemand nam.
     102    const raw = Object.prototype.hasOwnProperty.call(settings, g.feature) ? settings[g.feature] : null;
     103    const beslist = raw && typeof raw === 'object' ? !!raw.decided : (raw === true || raw === false);
     104    const value = raw && typeof raw === 'object' ? raw.value : raw;
    100105    // De trap: het bovenliggende moet OPEN staan. Onbekend telt niet als dicht --
    101106    // bij een ward elders kennen we de stand niet, en verbergen betekende daar
    102107    // ooit dat een voorstel nooit geopend kon worden.
    103     const blockedBy = g.needs && settings[g.needs] === false ? g.needs : null;
     108    const bovenliggend = settings[g.needs];
     109    const bovenWaarde = bovenliggend && typeof bovenliggend === 'object' ? bovenliggend.value : bovenliggend;
     110    const bovenBeslist = bovenliggend && typeof bovenliggend === 'object' ? bovenliggend.decided : (bovenWaarde === true || bovenWaarde === false);
     111    // Alleen dichthouden als we ZEKER weten dat het bovenliggende uit staat.
     112    const blockedBy = (g.needs && bovenBeslist && bovenWaarde === false) ? g.needs : null;
    104113    return {
    105114      feature: g.feature,
     
    107116      reversible: !!g.reversible,
    108117      value,
     118      decided: beslist,
    109119      // Vast staat vast: tonen mag, verzetten niet.
    110120      adjustable: !g.fixed && !blockedBy,
     
    274284}
    275285
     286/**
     287 * De stand van een gate zoals DEZE guardian hem kent.
     288 *
     289 * Er zijn geen lokale accounts: elke ward woont op een andere server, dus de
     290 * kolom op onze eigen sites-tabel is voor een ward altijd leeg. Wat een guardian
     291 * wel heeft is de UITSLAG van besluiten -- een geaccepteerd voorstel met waarde
     292 * true betekent dat de poort openging.
     293 *
     294 * Geeft { value, decided }:
     295 *   decided true   we hebben een aangenomen besluit gezien; value is die waarde
     296 *   decided false  we hebben er geen; value is de standaard voor een ward (uit)
     297 *
     298 * Dat verschil hoort zichtbaar te blijven. "Uit" en "voor zover wij weten uit"
     299 * zijn niet hetzelfde, en het tweede is wat we meestal hebben.
     300 *
     301 * BEKEND GAT: dit ziet alleen onze EIGEN voorstellen. Antwoordde je op dat van
     302 * een mede-guardian, dan komt de uitslag wel binnen (gated_outcome) maar wordt
     303 * hij niet bewaard -- handshake.js legt alleen vast voor sent-rijen die van ons
     304 * zijn. Een gate die een ander heeft geopend leest hier dus als "uit". Dat is de
     305 * onveilige kant en het hoort gerepareerd te worden.
     306 */
     307export function knownSetting(guardianSlug, wardUri, feature) {
     308  try {
     309    const r = db.prepare(`SELECT value FROM ap_gated_sent
     310                           WHERE guardian_slug = ? AND ward_uri = ? AND feature = ? AND status = 'accepted'
     311                           ORDER BY created_at DESC LIMIT 1`).get(guardianSlug, wardUri, feature);
     312    if (r) return { value: !!r.value, decided: true };
     313  } catch { /* val terug op de standaard */ }
     314  return { value: false, decided: false };
     315}
     316
    276317export function settleSent(offerId, outcome) {
    277318  try { db.prepare('UPDATE ap_gated_sent SET status = ? WHERE offer_id = ?').run(outcome, offerId); } catch { /* non-fatal */ }
     
    299340
    300341export default {
    301   GATE_CATALOGUE, gateRows,
     342  GATE_CATALOGUE, gateRows, knownSetting,
    302343  tallyGatedSetting, thresholdFor, featureColumn, recordGatedVote, gatedProgress, GATED_WINDOW_MS,
    303344  parseGatedSetting, buildGatedOffer, rememberGatedOffer, recallGatedOffer,
Note: See TracChangeset for help on using the changeset viewer.