diff --git a/forum-network/notes/forum.md b/forum-network/notes/forum.md index 2a3f76a..8057d1b 100644 --- a/forum-network/notes/forum.md +++ b/forum-network/notes/forum.md @@ -10,3 +10,11 @@ Effective power can be considered as a flow rate of posts; (value per post) / (d Internal energy is similar to Forum total value / DAO total reputation Total available reputation is similar to thermodynamic free energy + +--- + +Examples to add: + +- Incinerator + +- Negatively cite a zero-value post -- intent is to show how governance might cite a post as a counter-example diff --git a/forum-network/notes/matrix.md b/forum-network/notes/matrix.md new file mode 100644 index 0000000..f5a0f5b --- /dev/null +++ b/forum-network/notes/matrix.md @@ -0,0 +1,9 @@ +Matrix is a communications network. +It has a client-server, server-server decentralized architecture. +Rooms are synced (eventually consistent) among all servers with clients participating in the room. + +Matrix supports "Application Services", which are limited to funcion in a passive mode, meaning they only piggyback on top of the existing protocols. + +Synapse, a Matrix server implementation, supports "Modules" + +The Matrix devs recognize the need for a robust reputation system and are in pursuit of funding and development for that purpose. diff --git a/forum-network/src/classes/dao/forum.js b/forum-network/src/classes/dao/forum.js index 6a6db0f..7826cca 100644 --- a/forum-network/src/classes/dao/forum.js +++ b/forum-network/src/classes/dao/forum.js @@ -3,7 +3,7 @@ import { Action } from '../display/action.js'; import { Actor } from '../display/actor.js'; import params from '../../params.js'; import { ReputationHolder } from '../reputation/reputation-holder.js'; -import { displayNumber, EPSILON } from '../../util.js'; +import { displayNumber, EPSILON, INCINERATOR_ADDRESS } from '../../util.js'; const CITATION = 'citation'; const BALANCE = 'balance'; @@ -27,11 +27,11 @@ class Post extends Actor { .reduce((total, { weight }) => total += weight, 0); if (leachingTotal > params.revaluationLimit) { throw new Error('Post leaching total exceeds revaluation limit ' - + `(${leachingTotal} > ${params.revaluationLimit})`); + + `(${leachingTotal} > ${params.revaluationLimit})`); } if (donationTotal > params.revaluationLimit) { throw new Error('Post donation total exceeds revaluation limit ' - + `(${donationTotal} > ${params.revaluationLimit})`); + + `(${donationTotal} > ${params.revaluationLimit})`); } if (this.citations.some(({ weight }) => Math.abs(weight) > params.revaluationLimit)) { throw new Error(`Each citation magnitude must not exceed revaluation limit ${params.revaluationLimit}`); @@ -70,9 +70,14 @@ export class Forum extends ReputationHolder { } async addPost(authorId, postContent) { + console.log('addPost', { authorId, postContent }); const post = new Post(this, authorId, postContent); this.posts.addVertex(post.id, post, post.getLabel()); for (const { postId: citedPostId, weight } of post.citations) { + // Special case: Incinerator + if (citedPostId === INCINERATOR_ADDRESS && !this.posts.getVertex(INCINERATOR_ADDRESS)) { + this.posts.addVertex(INCINERATOR_ADDRESS, { name: 'Incinerator' }, 'Incinerator'); + } this.posts.addEdge(CITATION, post.id, citedPostId, weight); } return post; @@ -171,22 +176,44 @@ export class Forum extends ReputationHolder { for (const citationEdge of citationEdges) { const { weight } = citationEdge; let outboundAmount = weight * increment; - const balanceToOutbound = this.posts.getEdgeWeight(BALANCE, citationEdge.from, citationEdge.to) ?? 0; - // We need to ensure that we at most undo the prior effects of this post - if (initialNegative) { - outboundAmount = outboundAmount < 0 - ? Math.max(outboundAmount, -balanceToOutbound) - : Math.min(outboundAmount, -balanceToOutbound); - } if (Math.abs(outboundAmount) > EPSILON) { - const refundFromOutbound = await this.propagateValue(citationEdge, { - rewardsAccumulator, - increment: outboundAmount, - depth: depth + 1, - initialNegative: initialNegative || (depth === 0 && outboundAmount < 0), - }); + const balanceToOutbound = this.posts.getEdgeWeight(BALANCE, citationEdge.from, citationEdge.to) ?? 0; + let refundFromOutbound = 0; - outboundAmount -= refundFromOutbound; + // Special case: Incineration. + if (citationEdge.to.id === INCINERATOR_ADDRESS) { + // Only a positive amount may be incinerated! Otherwise the sink could be used as a source. + if (outboundAmount < 0) { + this.scene?.flowchart?.log(`style ${citationEdge.from.id} fill:#620000`); + throw new Error('Incinerator can only receive positive citations!'); + } + // Reputation sent to the incinerator is burned! This means it is deducted from the sender, + // without increasing the value of any other token. + this.actions.propagate.log(citationEdge.from.data, { name: 'Incinerator' }, `(${increment})`); + } else { + // We need to ensure that we at most undo the prior effects of this post + if (initialNegative) { + outboundAmount = outboundAmount < 0 + ? Math.max(outboundAmount, -balanceToOutbound) + : Math.min(outboundAmount, -balanceToOutbound); + } + + // Recursively propagate reputation effects + refundFromOutbound = await this.propagateValue(citationEdge, { + rewardsAccumulator, + increment: outboundAmount, + depth: depth + 1, + initialNegative: initialNegative || (depth === 0 && outboundAmount < 0), + }); + + // Any excess (negative) amount that could not be propagated, + // i.e. because a cited post has been reduced to zero value, + // is retained by the citing post. + outboundAmount -= refundFromOutbound; + } + + // Keep a record of the effect of the reputation transferred along this edge in the graph, + // so that later, negative citations can be constrained to at most undo these effects. this.posts.setEdgeWeight(BALANCE, citationEdge.from, citationEdge.to, balanceToOutbound + outboundAmount); totalOutboundAmount += outboundAmount; diff --git a/forum-network/src/classes/dao/validation-pool.js b/forum-network/src/classes/dao/validation-pool.js index 4781608..d288b29 100644 --- a/forum-network/src/classes/dao/validation-pool.js +++ b/forum-network/src/classes/dao/validation-pool.js @@ -54,8 +54,7 @@ export class ValidationPool extends ReputationHolder { || [null, undefined].includes(duration) ) { throw new Error( - `Duration must be in the range [${params.voteDuration.min}, ${ - params.voteDuration.max ?? 'Inf' + `Duration must be in the range [${params.voteDuration.min}, ${params.voteDuration.max ?? 'Inf' }]; got ${duration}`, ); } diff --git a/forum-network/src/index.html b/forum-network/src/index.html index d587684..03916ad 100644 --- a/forum-network/src/index.html +++ b/forum-network/src/index.html @@ -21,6 +21,9 @@
  • Redistribute power through subsequent support
  • Destroy a post after it has received positive citations
  • Initially zero-valued posts later receive citations
  • +
  • Negatively cite a zero-valued post
  • +
  • Incinerate reputation
  • +
  • Use incineration to achieve more balanced reweighting