Programmer's Guide ================== Dependencies ------------ Apache2 This is the web server. Other web servers could be substituted. I chose Apache because it is the premier free and open source web server. Also, because it has mod_wsgi, it is simpler to setup for deploying Django apps. Apache2 mod_wsgi For interacting with Django (using the Python WSGI standard directly instead of CGI) django Web framework: provides user login and registration; generates the client-side HTML and javascript pages to serve in response to user actions. (It also has its own basic webserver, which could be used to try out the Allsembly™ program without installing Apache.) graphviz graphviz-dev The Python library "PyGraphviz" relies on these. Graphviz is used to draw the graphs. Problog A probabilistic programming language. This is used to compute the probabilities. ZODB An object database. This is used for persistence. It stores all of the persistent objects. The default backend is file storage, which is currently being used. Other storage backends could be used in the future for better scalability, see :ref:`Design for scalability`. PyGraphviz Easy to use Python bindings to the Graphviz library. RPyC Python to Python RPC used to communicate between the Django services and the Allsembly™ server. It could be useful later for implementing communication with a registration server. (See :ref:`Design for confidentiality`.) persistent This works with ZODB to automatically save and restore objects that subclass "Persistent". transaction This provides a transaction manager that is used with ZODB. atomic This provides an atomically updatable integer class. readerwriterlock This provides thread synchronization using separate locks for readers and writers. There can be multiple readers but only one writer. python-daemon This provides an easy API for making a Python program run as a Unix daemon. d3.js This is a graphics library for web clients. I am currently only using it for pan and zoom of scalable vector graphics (SVG) that is the format of the argument graph. It could be used to draw alternative layouts of the argument graph on the client-side if desired, especially when accompanied by *d3-graphviz*. dialog-polyfill.js This provides the HTML DIALOG tag and its functionality for browsers that don't (fully) support it, yet. The DIALOG tag is used for creating the modal dialogs. jquery-3.6.0.js Used to simplify AJAX calls (asynchronous loading of web content using JavaScript). Future possible dependencies ---------------------------- GPGME for encrypting the stream encryption keys with the public key(s) of the admins. (The stream encryption key will also be encrypted with the user's hashed password.) See more details about this in the section :ref:`Design for confidentiality`, below). PyNaCl for stream encryption or salsa20 to encrypt a database field containing users' anonymized ids (see more details about this in the section :ref:`Design for confidentiality`, below). Pyrsistent to avoid mistaken call by reference-like behaviors (and, therefore, subtle bugs). returns to replace exceptions for error handling. Files ----- | requirements.txt | List of required dependencies and their version numbers | | setup.cfg | Configuration options for mypy and configuration options for Pylint | | allsembly/ | All of the modules of the Python package | | django_app/ | App for communicating with users to log them in and to generate | the html and JavaScript of the site. It communicates with the | AllsemblyServer to provide the services. | | django_site/ | Configuration information for the Django site, which uses the | Django app, the code for which is in the django_app directory. | | docs/ | | _build/ | The Sphinx-generated HTML documentation, as a git submodule | | conf.py | The Sphinx configuration file. | | fdl-1.3.txt | The GNU Free Documentation License | | index.rst | The main file of the documentation | | how_it_works.md | This file explains how human participants contribute to making the probabilistic estimates of the truth or correctness of conclusions possible, including a contrived example. | | make.bat | | Makefile | Files for building the documentation. Sphinx is required. | | notes.md | This file contains an overview of the dialogue procedure and why it is expected to be effective, including notes about a few salient design issues. | | LICENSE.third-party/ | Licenses for third-party software distributed with Allsembly™ | | misc/ | Documents containing additional explanation about what Allsembly™ is about and the theory behind it--these files are not part of the documentation, and might be edited for publication elsewhere at some point. | | prospectus.pdf | This file contains a scholarly presentation of the initial development of the theory and concepts that are behind this software prototype and includes some of the motivation as well. | | scripts/ | | allsembly-server.py* | Use this script to start the Allsembly™ server. Run it with the ``--help`` option to get usage information. Also, see, the section :ref:`Installation and Testing` for some instructions. | allsembly.service | A systemd service script example. Modify the line "ExecStart"; then use this file to make the allsembly-server.py persistent as a daemon (i.e., make it available on system startup). | | test/ | The tests. | | web/ | scripts/ | The javascript libraries Specification of requirements (draft) ------------------------------------- More is to be added to this section later. Make all of the argumentation and discussion publicly accessible. This will support a secondary function of having a kind of encyclopedia of arguments pro and con issues for repeated reference. Users should be able to obtain an independent URL to any part of an argument or discussion so as to refer to any specific aspect of that argument or discussion. The data (only completely anonymous or anonymized data) should also be available in a format like Argument Interchange Format (XML-RDF) or CSV (comma-separated values), for computer assisted processing and exploration. (Public accessibility is not currently implemented.) Future requirement: provide for third-party clients; maintain a stable client interface. Design overview --------------- .. uml:: classes.uml .. uml:: sequenceDiagram.uml The client-side code is generated by the Django templates in django_app/templates according to the code in django_app/views.py. It communicates with the Allsembly™ server using RPC (provided by the RPyC library). The code on the Allsembly™ server side is in the rpyc_server.py module, especially the AllsemblyServices class. The interaction proceeds as shown in Figure 2, above. Currently, since there is no interaction between users--each user is in a kind of *sandbox* of its own--which graph to display is dependent on which user is logged it (i.e., the userid in the encrypted login cookie). The UserServices object is used to provide each of the specific services that require login, and it is provided with a login username by the django_app, which must have logged in the user. In most cases, the request is just added to a queue. The AllsemblyServices RPyC server object is running its event loop in a separate thread from the server main loop. The server main loop, allsembly.allsembly.AllsemblyServer.server_main_loop(), is started by the script, "scripts/allsembly-server.py", and it, in turn, starts the RPyC service in a separate thread. In the main loop, each queue is checked and the requests there are processed. Most of the processing involves calling functions in an ArgumentGraph object. There is a separate ArgumentGraph object for each graph and it is stored in a mapping that is persisted in the database. The ArgumentGraph object draws a new graph and calculates new probabilities with each client request that changes the graph. Currently, after the client makes a request that changes the graph, it immediately after that requests a new drawn graph. The intention is that in a future version, the client would be subscribed to a server sent events or websockets channel or be waiting on a long poll, to learn when a new graph is ready to be loaded. Class detail ------------ For now this section just contains the docstrings from the modules. **allsembly** module ^^^^^^^^^^^^^^^^^^^^ .. automodule:: allsembly.allsembly :members: **rpyc_server** module ^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: allsembly.rpyc_server :members: **demo** module ^^^^^^^^^^^^^^^ .. automodule:: allsembly.demo :members: **user** module ^^^^^^^^^^^^^^^ .. automodule:: allsembly.user :members: **argument_graph** module ^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: allsembly.argument_graph :members: **prob_logic** module ^^^^^^^^^^^^^^^^^^^^^ .. automodule:: allsembly.prob_logic :members: **betting_exchange** module ^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: allsembly.betting_exchange :members: **speech_act** module ^^^^^^^^^^^^^^^^^^^^^ .. automodule:: allsembly.speech_act :members: Future design ------------- Design for confidentiality ^^^^^^^^^^^^^^^^^^^^^^^^^^ *This section and the next two sections, "Design for integrity" and "Design for scalability" describe features that are not expected to be added to the prototype. They would be added later, in a stage of development beyond the prototype. But they contain important ideas to keep in mind while developing the prototype.* .. image:: images/anonymity_preserving_registration.* The figure above shows a design with a separate server for login and a separate server for registration, which could be hosted by different organizations. The organization hosting the Registration server verifies the new user's identity but never sees the user's userid or passwords; those are encrypted on the client side using the public key of the organization hosting the login server. The basic idea is that records containing the userid and records containing the personally identifying information (PII) are not connected by any common fields, and cannot be connected without the private key of the ID guardian. (One can imagine the ID guardian as a law firm with it's private key stored offline in a vault or something or escrow service that is somehow contractually bound not decrypt the userid field in a database record provided to it from the registration database by the registering organization without, say, a court issued warrant.) The idea does not necessarily require multiple organizations or servers and separate DBMSes, though. It can be accomplished in a single database managed by one DBMS. A record in the login table contains, e.g., userid and password. A record in the registration database contains, e.g., real name, email address, phone number, address, etc., and encrypted userid (that was encrypted by the client's device before it reached the server and that can only be decrypted using the private key held offline). The flow is as follows: #. User connects to the registration server and provides personally identifying information that will be used to verify their identity and provides a desired userid that is encrypted with a public key of the login server (the Allsembly™ server). The corresponding private key is stored unencrypted on the login server. #. The registration server sends only the encrypted userid and password to the login server. #. The login server informs the registration server whether the userid is unique. If it is not, then the registration server informs the user to select a new userid. #. If the userid is unique, the login server stores the userid and password in its login database (table) with a flag indicating that it is not yet activated (because the user has not yet been verified). #. The registration server discards the encrypted password and further encrypts the already encrypted userid with the public key of the ID guardian. It stores this encrypted userid with the PII in the registration database (table). (The encrypted userid should not be able to be compared with a the same userid encrypted with the same key at a different time. Therefore, this saved userid might have been separatedly encrypted from the one sent to the login server, with a different random padding.) #. The next step is not fully worked out. It involves passing a token that proves that the user has been verified. It possibly involves cryptographic signatures and is done in such a way that neither the login server nor the registration server may use its counterpart to send arbitrary encrypted messages to the user. (Imagine that there is limited trust between them.) #. After the user has been verified, the user logs in to the login server. Subsequently, the user uses the login server to change their password. (Or the client might log in to both servers to change passwords, separately on both, in such a way that it only requires one step for the user.) If the user needs to change their PII, they log in to the registration server using their email adress. (They could potentially use the same password hashed and salted differently.) To enable recovery of a forgotten userid, userid could be stored by the registration server (or in the registration database) encrypted with the user's password. The password is not stored bythe registration server, except possibly in hashed form, so the userid is encrypted using the password hashed with a different algorithm and/or parameters. In that case, the user logs into the registration server using email address and password; then, the registration server sends the encrypted userid to the user who decrypts it client-side. There seems to be no way to recover a forgotten password without temporarily breaching anonymity for that user. Although the user has both email address and userid, the user cannot authenticate with the login server using an email address without connecting the identities, so password reset via email would only get a user access to their profile on the registration server. If the ID guardian is a separate person/organization from the organization hosting the login server, then the representatives of both organizations are needed to revoke anonymity. NOTE: THIS IS NOT A PROOF. THERE COULD BE IMPORTANT FLAWS IN THIS APPROACH. However, I believe the approach has the following desirable properties: #. Attacker cannot learn identities of users by listening to traffic between client and server, without other information. #. Attacker cannot learn identities of users by obtaining either or both databases (tables). #. Attacker cannot learn the identities of existing users by controlling either or both servers. (Such an attacker can only learn identities of new registrants andd users resetting their passwords.) An additional issue for confidentiality is the connection of bets on positions to userids. To prevent a whole profile of a user's argumentative commitments being built up by an attacker, ids used to match users with betting contracts can be anonymized. The list of anonymized ids that correspond to a userid can be maintained as an encrypted field in the database table containing user information. The encryption key can be the user's password itself hashed in a different way and with a different salt than the one stored for login. So, when a user logs in they send both hashes. The server decrypts the anonymized ids field and caches it for a while to provide the services to the user. It remains encrypted at-rest and anytime the user logs out or the cache expires. Design for integrity ^^^^^^^^^^^^^^^^^^^^ *This section describes features that are not expected to be added to the prototype. They would be added later, in a stage of development beyond the prototype. But it contains important ideas to keep in mind while developing the prototype.* To provide accountability that the data stored on the server matches the users' activities, the server should send cryptographically signed receipts for bids, asks, and betting contract purchases and sales. The client can store them in local memory and can also store pending transactions to re-send in case it does not get a confirmation receipt. Likewise, users should not be able to repudiate their orders or betting contracts. So, those should be cryptographically signed by users as well. Design for scalability ^^^^^^^^^^^^^^^^^^^^^^ *This section describes features that are not expected to be added to the prototype. They would be added later, in a stage of development beyond the prototype. But it contains important ideas to keep in mind while developing the prototype.* The current design was not made for massive scalability. This section is just to add information about what can be done to scale the existing design without extensive changes. First of all different database backends can be dropped in as replacements. The ZODB API supports ZEO, which is a multi-process available, networkable DBMS. It also supports a "Relstorage" backend, which allows for storage in SQL databasaes such as MySQL, PostgreSQL, and commercial enterprise-scale SQL DBMSes. However, it still stores the objects pickled. An alternative would be to use an SQL DBMS through an object-relational mapper (ORM) to possibly eek out some better concurrency. It might not be necessary to do that, though. I assume that I will eventually have to replace Problog. It is slow because of the knowledge compilation step. It is intended to improve processing when many queries are made against the same graph, which is not quite my use case. A promising alternative possibility may be to use iterative join-graph probagation (IGJP), which is an "anytime" algorithm for evaluating Bayesian Networks. At each iteration, it gets closer to the exact solution (but it is only exact inference when the "join graph" is a "join tree"). So, the graph could be updated with the approximate values computed so far. There is an existing open source implementation in a software package called `"merlin" `_. It could be integrated into the Allsembly server. It is single threaded. However, I would like to investigate parallelizing the algorithm. There is a dependency of a node on the node from which it receives a message in IJGP (and in other message passing belief propagation algorithms). But it seems like there would be many graphs that would have multiple semi-independent paths parts of which could have their calculations independently computed by separate worker threads. I also intend to investigate algorithms for dynamically updating graphs without losing all of the previous inference or knowledge compilation work. Regarding exact versus approximate inference, since the primary purpose of evaluating the positions in the dialogue after every move and not only at the end of the dialogue or at other key points, such as when considering extending the time-limit for the dialogue, is to guide participants in choosing the most efficient next moves, a good enough approximation should be adequate to the purpose. Exact inference could be used at the end and, possibly also, at other key points in the dialogue. The approximation needs to be good enough that it does not or only rarely does lead participants to expend their efforts attacking or supporting positions that are not in need of it or doing so when there would be much better targets for attack or support given their beliefs about the evidence and the correctness of various positions. The evaluated estimate of the confidence that the group of participants as a whole has in aggregate in the weight of evidence supporting a position functions in a similar way to a *burden of proof*. When the value is less than 50%, it indicates that advocates of that position will 'lose' (that is, not have their preferred position be considered justified) if nothing changes before the end of the dialogue. Therefore, as long as they continue to believe that there is evidence to decisively support the position, it is incumbent on them to provide it (subject to their priorities--some other position might be more important to them to focus their efforts on). On the other hand, when the position assessed at greater than 50%, those opposed have the burden of producing evidence while they continue to believe that the position (in and of itself or because of what it supports) is important and that there is decisive evidence opposed to it. So long as the appoximation guides, with high frequency, the participants to make the same strategic assessments as the exact result would, the system will be functioning well (efficiently). Other than that, I would propose parallelising the Allsembly™ server using separate processes, with each process handling one or more complete issues (whole argument graphs). The separate processes would have to coordinate with regard to users needing to participate in issues--a user may participate on multiple issues overlapping in time--being handled in another process or being handled in multiple processes. Such changes, which are not too extensive with regard to modifications to the existing design, might enable a lot of scalability and be sufficient for the Allsembly™ project beyond the prototype. Massive scalabily could be part of a separate (we could hope funded) project if it, at some point, becomes a widely used piece of software. Localization ^^^^^^^^^^^^ UPDATE: Part of this can be handled using Django. More information to be added. I would still like to use XML in order to give clients more control over the presentation, but XML containing the translated strings can be generated by Django. The default XSL can also be generated by Django, but in advance, rather than on-the-fly. My current intention is to implement localization by putting the strings in XML files and using XSLT transforms to select the appropriate string and to combine it with any dynamic data. The Accept-Language header or the user's language selection (stored in a cookie or embodied in a special path, such as /en/file.xml) can be used to select the appropriate string. Directives in XML tags can encode the correct way to transform dynamic data or other words in the text that are dependent on the dynamic data. For example, if the dynamic data is a number, another word might have to be sometimes singular and sometimes plural: "You have x token(s) remaining." Sometimes there might be special words when the number is 2 or 3. Sometimes words might need to be marked with affixes or suffixes to do with grammatical role. These things could be accomodated with regular expressions and XSLT regular expression functions. The same or similar methods can be used to accommodate differences in date, time, and number formats or separators between items in sequences. Alternatively, some format preferences could be handled using special code in the server. For example, the server could be given the user's preference for probabilities as decimal values or percentages and preference for dot or comma separating the whole and fractional parts of a number, etc., and the server would thenceforth produce probabilities that way, or it could be handled with XSLT and (possibly complex) regular expressions or conditionals. Benefits of this approach could be: * XML and XSLT processing are built into web browsers. * Javascript isn't required (but could be used). * XML schemas could validate the documents using readily available tools * XML is a commonly used standard. The developer might already know it; otherwise, it may be useful to learn and reuseable knowledge. Project development roadmap --------------------------- Accessibility basics ^^^^^^^^^^^^^^^^^^^^ * Add text description to SVG diagram of the dialogue graph that describes the graph structure. * Add keyboard controls for zooming and panning the SVG image. * Maintain the page layout reasonably when the page is scaled with ctrl-+/-. Core features ^^^^^^^^^^^^^ * Enable a user to reuse existing positions to support or oppose other arguments. * Enable a user to mark two or more positions as the same or as mutually exclusive (the "Relate" feature). * Enable a user to add posts to a per-position informal discussion (the "Discuss" feature). * Implement the betting markets, including the order book, the matchin algorithm, and the ledger of bids and betting contracts. * Enable the (re-)selling of existing betting contracts. * Implement detection of inconsistent bids and bets and prevent users from making such. * Implement detection of inconsistencies in other commitments (as the result of reductio arguments and some "Relate" actions) and enable users to resolve inconsistencies by selling betting contracts. * Enable topic proposal. * Enable users to interact on the same dialogues (not only single user sanboxes and simulated multi-user activity). * Add policy proposals as the initial position type and add a policy evaluation positon type and the other policy decision features. * (For possible inclusion in the prototype:) Add encryption of anonymous IDs that connect a user to their bids and bets in the ledger. * (For possible inclusion in the prototype:) Add asymmetric encryption of userids in a registration record to prevent its connection with user login records, as described under :ref:`Design for confidentiality`. If this is added in the prototype, it will be an optional feature and only use a single public key, not two. Demo features ^^^^^^^^^^^^^ * Enable deletion of positions. * Add a guest login option. * Allow a user to simulate multiple users by selecting the current user from a dropdown menu. More to be added to this section, including categorizing items as short-, medium-, or long-term and possibly including beyond-the-prototype items, later. Coding standards ---------------- NOTE: This project is uses typed Python. The mypy settings are in the file setup.cfg. It uses all of the settings from ``mypy --strict`` (as of mypy version 0.812) except ``--disallow-subclassing-any``, which is not used (especially) since some classes subclass "Persistent" in order to take advantage of the ZODB database. The modules may be type-checked using the following command from the command line from within the main directory of the project: ``mypy allsembly/*.py``. It should report no errors. For more information about mypy or about optional type-checking in Python, see http://mypy-lang.org. Mypy may be installed with: ``python3.7 -m pip install mypy``. Settings for Pylint (see https://pylint.org) are also in the setup.cfg file. With Pylint installed, the modules may be linted by running Pylint from the command line as follows: ``pylint --rcfile=setup.cfg allsembly``. The Pylint settings in setup.cfg correspond to: ``pylint --disable=all -enable F,E,W --disable=python3``. This will report many warnings, mostly about unused variables and two errors about imports. The errors are false positives as far as I can tell. The module is successfully using the imported class (OOBTree). I plan to attend to the warnings. I also look at the output of the refactoring module even though it is disabled in setup.cfg, and I plan to implement some of its refactoring recommendations. Guidelines ^^^^^^^^^^ Python: * In the server modules, don't use exceptions and don't allow exceptions to escape your functions (it is okay in scripts). Unhandled exceptions could be the source of unplanned server termination that could affect data integrity or worsen user experience even though the server can be restarted. I will be reviewing the "returns" Python library to help with this in the future. * Avoid the use of variables when possible and reasonable and annotate variables as "Final" whenever they do not need to be reused. Reuse few variables. * Avoid unnecessary references. I am considering the "Pysistent" Python library to help with this in the future. * Make use of the context manager ("with ...:" blocks) for resource managemant. * Mark private data and functions with a leading underscore (Pylint will catch unintended uses). * Use all caps for constants (Pylint will catch unintended uses). * Use docstrings to document all modules, classes, and nontrivial functions. JavaScript: * Use only as much JavaScript as necessary. * Prefer declarative code to imperative whenever imperative code is not needed to provide a significant advantage. * Use comments to document all files and nontrivial classes and functions. Other languages: Adopt similar guidelines. Secure coding: See the "OWASP Secure Coding Practices Quick Reference Guide" at: https://owasp.org/www-project-secure-coding-practices-quick-reference-guide/migrated_content Choosing library dependencies: * Choose the most widely uses and respected libraries for encryption. * For other purposes, choose more or less production ready libraries. How it works ------------ For now, see `docs/how_it_works.md `_ in the `source code repository `_. Other uses ---------- For example, the software could be adapted to provide a way for writers to distribute bounties to people who help to improve their writing by finding shortcomings in the reasoning. Aside from adapting the code, if one wants to use it in such a way, one needs to be cognizant of any laws in one's jusrisdiction restricting *contests*, including ones that contain an element of chance. Individuals or small groups could provide bounties for a recommended resolution of some disagreement. Private groups could use it without bounties to deliberate among themselves. If any money is exchanged, for example, grafting a parimutuel betting scheme onto the betting market aspect of the software, then one needs to be cognizant of any laws in one's jusrisdiction restricting *gambling*, and possibly also laws in the jurisdictions of each of the participants if those are different. While Allsembly™ as a community is intended to be independent in the sense of participants choosing their own issues to dialogue about, the software could also be adapted for public consultation in which issues and possibly some other parameters for the dialogue are decided by the organization seeking the policy recommendation to be generated through the dialogue. It could be used for opinion research in conjunction with opinion polls, e.g., by comparing opinion before and after deliberation (as with Deliberative Polling®) or by comparing the recommendation yielded by deliberation (if any) with an opinion poll result. It could be used for argumentation or AI research by mining (only completely anonymous) data, such as for training an artifical agent how to argue or deliberate based on the activity of the human participants.