Continuity of government

France just had their fourth Prime Minister in two years removed after losing a vote of no confidence. President Macron states that he will appoint a new one within a few days. That seems pointless. To lose one Prime Minister to a vote of no confidence means you don’t have the backing of the legislative assembly and it’s no good bashing your head against that wall hoping that somehow you will find yourself wielding a majority.

First a recap if you haven’t followed this: President Macron called for early parliamentary elections in 2023 because the EU-elections had shown that the electorate had substantially different allegiances than what was represented in the French parliament. The election lead to the current deadlock where no one commands a majority. Macron was blamed for this but I think he did the right thing. There was ample evidence that the electorate had changed their allegiances and the actual election bore this out. That a parliamentary deadlock resulted is the choice that the electorate made.

I think a reasonable critique of president Macron is that he should also have called for earlier presidential elections when the parliamentary vote showed that his group of supporting parties no longer commanded a majority. He did not do that. This seems inconsistent. Why first honour the spirit of the law(well, the constitution technically) in calling for early parliamentary elections if you then go on to hold high the letter of the law when there is equal evidence that the electorate no longer support the current president?

But this just crystallises the issues seen growing throughout Europe over the last twenty years: deadlock. Belgium, Northern Ireland, Sweden and France are just the first examples that spring to mind. In the case of Belgium they had no elected government for more than 500 days. In Northern Ireland they had a technocrat government for years, ostensibly because one party didn’t like the post-Brexit arrangement but in reality it was quite convenient for all parties to let non-politicians make a bunch of difficult decisions. In Sweden we didn’t have an actual work stoppage, merely the formation of unstable governments that struggled to maintain coherency.

It is my argument that this is bad. Technocrat governments are all well and good as a fallback mechanism but it is hardly beneficial if the government doesn’t represent what the electorate voted for, even when the way in which a deadlock was reached was through elections. If nothing else a government needs to be able to respond to emergencies. If someone hijacks a plane and there is disruption in air traffic and a bunch of other countries worried about their citizens being caught up in the situation, you are just making a fool of yourself saying “We have no one to make hard choices or balance different viewpoints for three weeks, please come back later”.

A long-term solution

How might we avoid deadlocks like these? Italy has an almost nuclear option where the largest party in the election results are given a bonus of extra seats in parliament. I don’t like this because it’s not proportional representation, where one vote equates to one equal part in the electoral process. Whoever voted for the party that got the most votes has their vote amplified to 120%, making all other voters demoted to only having 80% the influence(no, the arithmetic is more complicated than that, this was just a crude approximation). Not all countries have proportional representation, most notably the US and the UK. They have a first-past-the-post system so only by receiving the most votes in a constituency do you get any representation. So in the UK the Greens might have support from 10% of the population but only get 5% of the seats in parliament.

This “Italian” solution can also suffer from factions in a single party causing deadlocks. We shouldn’t assume that only deadlocks between parties can cause issues. So I suggest the following constitutional setup:

  1. A Caretaker government is formally recognized as being one that has been appointed by the legislative assembly but no longer commands a majority in that assembly(typically because they lose a vote of no confidence or because a parliamentary election is held).
  2. A Caretaker government can introduce new laws without parliamentary support unless the head of state blocks them(we need some checks and balances).
  3. A Caretaker government can be replaced as soon as the legislative assembly – through a majority vote – appoints a new government.

In the French case the government that ran the country before snap parliamentary elections were held would have stayed in power and would have been able to rule by decree. The French parliament would not have been asked to approve any reforms or budgets the government proposed. The government would just have all these things take effect without parliamentary approval. This seems very undemocratic but it is only slightly undemocratic. It’s still a government elected by the legislative assembly which in turn is a representation of what the electorate wants, just running past the most recent election and not requiring parliamentary approval for changes.

But this is not meant to remain the case for more than a few days or at most a few weeks before a new parliamentary majority is formed and a new government is appointed. But as is the case in France today, the old government would still be in charge since no parliamentary majority currently exists, two years after the most recent elections. The government themselves could say “We don’t think we have the proper mandate to run the country but there are three blocks in parliament refusing to agree on a new government so find ourselves still in power whether we like it or not…”

And this to me seems like a good sword of Damocles to hang over the various factions: agree on a new government or explain to the electorate why you have left the previous government in charge all this time. So the whole Caretaker government scheme is mostly meant as a big stick with which to pound parliament to at least agree on a government, but also serves as a workable plan B just in case the parliament is completely unwilling to… do things. Because as noted earlier, a country needs a government in place at all times, not just when parliament happens to see it fit to appoint one.

Complications

A Caretaker government would be expected not to diverge significantly from what the electorate seem to want at that point in time, even if that is quite different to what the government in question was elected to do some years back. This then becomes a little bit of a concern for whatever government is appointed by parliament, they may have to enact policies quite different to what they have themselves espoused if they find themselves lacking parliamentary backing. This can’t realistically be codified into the constitution and would only be an expectation, not a formal requirement. France demonstrates this quite well by the electorate voting in favour of various mutually exclusive factions, none of whom command a parliamentary majority. What even would a Caretaker government be expected to pursue? Making decisions that are unpopular in parliament can be both formally and operationally necessary.

The head of state would have the right to veto anything proposed by a Caretaker government. In France this would be the President but in Sweden it would be the King, which isn’t really viable for domestic political reasons. So the head of state isn’t necessarily the right person to wield veto powers over a Caretaker government. In Sweden the Supreme Court seems acceptable, because this is just to keep an outgoing government from abusing their last two days in office by outlawing all other political parties or passing a budget where no taxes are collected or something similarly malicious. In the former case the reform would have been struck down legally anyway, but this way it doesn’t even rise to the level of being seriously considered.

I have made it sound like once parliament agrees on a new government, all is well and we have continuity of government, but that is not the case. It would be perfectly feasible for the French parliament to appoint a government that no faction particularly likes but is deemed acceptable, only to then let the government achieve nothing. It’s not against the rules to vote against every single proposal put forward by a government you gave your support in parliament. This leads us to some awkward considerations.

One solution is to say that budgetary proposals have a special voting procedure. In the first round it works like today, you need a majority of all votes in parliament. The second round sees the smallest party ignored, all their votes are automatically set as “Abstains”. You keep going like this until only two parties remain. Now, this isn’t guaranteed to lead to a budget as the two largest parties could both vote “No” in this final round. However, I would argue that is the same as saying that the government has lost its parliamentary support and become a Caretaker government which can pass budgets without parliamentary approval. So a new budget still goes on to become binding.

Parliament could in that situation agree to create a new government just to get rid of the Caretaker government but to constantly go back and forth between party A and party B agreeing on a government only to later that same day agree on a vote of no confidence against the very same government makes these parties look pretty silly. Defining what constitutes a “budgetary proposals” is harder than it might seem. It’s trivially true when a formal budget is put forward but what about a separate legal instrument that requires enough funding to raise taxes by 1%? Either taxes are raised or existing expenditure is reduced to accomodate that change. Almost everything has some impact on state finances and the budget that was passed would really need to change to truly reflect what income and what expense is predicted*.

Another solution could be to mandate that parliament must have a budget in place by some date and if they fail to do that the president can put one in place covering the next period(usually a year). This raises similar questions as in the previous solution. What if parliament votes a law into force that prevents the Treasury from funding defence or health-care or whatever the parliament opposes at that particular point? In both solutions it makes sense to put in place a constitutional ban against any legal instrument that defunds, restricts or in some other way hinders the budget from being implemented. That’s precisely the sort of line in the sand that is going to be something that the supreme court has to define. Parliament will vote for a law, someone will say it undermines the established budget and the court has to rule on the subject. It can’t be exhaustively defined ahead of time.

Note that I’m not suggesting that we rule illegal everything that in some way hampers the implementation of the budget. There are a great many things that can’t keep a state from successfully implementing a budget, ranging from lower than projected tax receipts, investors not buying the state’s bonds and so on. You only look foolish if you declare them illegal. Zimbabwe for instance outlawed inflation when printing huge amounts of currency turned out to not improve the lives of the people of that country. It didn’t yield the results the government had promised, needless to say. But keeping parliament from interfering with the established budget is a reasonable restriction.

A short term solution

In most countries constitutional changes like the ones I propose above take time. In Sweden there must be two parliamentary votes separated by at least one general election to make a consitutional amendment. So in France they can’t really solve their current problem through constitutional changes. But Macron’s party Renaissance(RE) and it’s supporters can emulate this in a sense. Them voting against a vote of no confidence would be right and proper in the first case but when the second vote of no confidence was called they should all have abstained, basically saying “Since the government we appointed lost a vote of no confidence, we lay down our votes in any vote of no confidence in this parliament.”

That would have made it sensible for Macron to appoint a left-wing government that would receive backing from a majority of parliament – now with the centrist-Macron block bowing out. Rassemblement National(RN) would have thrown a hissy fit and accused RE of electing a left-wing government, but they would probably just say “No, the French people decided on that in the most recent election. We’re not voting for or against anyone at this stage and if this new government loses a vote of no confidence we urge the left-wing block to lay down their votes in future.”

This is a pretty harsh solution to attempt and some considerations should be taken into account. This would largely burn RE’s bridges with RN for the foreseeable future. Even if this forces RN to support Macron’s government it would be a short-term gain. RE and its supporters I think should play a different game and accept that they got thrown out of power by the French people. Burn your political mandate on the pyre of continuity of government and accept that this will make your vote-share go even lower, trusting your political opponents to make you look good in comparison as time goes by. Your popularity has to get worse before it can get better. It need not necessarily get better, but your only chance right now goes by heading down hill first.

A socialist government

So would a socialist government be good for France? I think it would be better than the current deadlock, but the I don’t think the socialist block will end up serving the French people well. I think a centrist and right-wing alliance would be better. But that’s not my call to make, that’s the decision of the French electorate. I don’t even have incontrovertible evidence of the socialist block’s impending failure, the rising cost of servicing France’s sovereign debt or the decreasing living standards that would ensue. If we had some Oracle-machine that showed us what the right answer was we would be on Easy street and could dispense with elections, but we don’t. So we just ask the electorate what they support and go with that, knowing full well that it might be the best route forward or it might end up harming the electorate well-being.


* A budget is not just a decision on what funds to allocate, it is a prediction of what income and expenses will be. The Region of Västra Götaland typically spend more than budgeted, which makes their budgets quite useless. There are statutory requirements of what certain branches of regional government must do and claiming year after year that you only allocate 90% of the money necessary to not violate the law is just silly. A person running a hospital won’t withhold medical treatment to save money because the budget said so, lest they find themselves facing criminal charges. A budget isn’t an instrument by which to achieve savings. Achieving savings can be entirely reasonable but a budget is not the instrument to do it. Statutory requirements for instance can only really be affected by turning to the legislative assembly which made the law in the first place.

OpenSCAP again

I plan to use Ubuntu Server 24.04 as the base for my network. They will be virtual machines running on Proxmox. Most will be unreachable from the internet and so I argue that they only need a baseline security level. Two nodes will however be directly accessible via the internet and so have to be hardened a few steps beyond the baseline. Let’s first make our own profile for Ubuntu 24.04!

cjp@fedora$ git clone https://github.com/ComplianceAsCode/content.git
cjp@fedora$ cd content
cjp@fedora$ python3 -m venv .
cjp@fedora$ vim products/ubunt2404/profiles/joholo_baseline.profile

Now what – pray tell – is in this baseline profile?

documentation_complete: false

title: 'Johan baseline profile'

description: |-
    A baseline profile for VMs based on Ubuntu 24.04.
    Meant for servers that aren't directly reachable from the internet
    and so are not required to be hardened as much as those that are.

selections:
    - var_password_pam_minlen=10
    - partition_for_boot
    - partition_for_home
    - partition_for_usr
    - partition_for_opt
    - partition_for_var
    - partition_for_var_log
    - partition_for_var_log_audit
    - accounts_no_uid_except_zero
    - accounts_root_gid_zero
    - accounts_password_all_shadowed
    - accounts_password_pam_minlen
    - accounts_password_pam_pwquality_enabled
    - accounts_umask_etc_bashrc
    - accounts_umask_etc_login_defs
    - accounts_umask_etc_profile
    - accounts_umask_root
    - no_duplicate_uids
    - file_permissions_etc_audit_auditd
    - file_permissions_etc_audit_rules
    - file_permissions_etc_audit_rulesd
    - grub2_audit_argument
    - package_audit_installed
    - service_auditd_enabled
    - audit_sudo_log_events
    - ensure_root_access_controlled
    - ensure_shadow_group_empty
    - check_ufw_active
    - ufw_rules_for_open_ports
    - disable_host_auth
    - chronyd_configure_pool_and_server
    - chronyd_run_as_chrony_user
    - ntp_single_service_active
    - sudo_require_authentication
    - sudo_remove_no_authenticate
    - directory_permissions_var_log_audit
    - sshd_use_strong_kex
    - sshd_disable_gssapi_auth
    - sshd_disable_kerb_auth
    - sshd_do_not_permit_user_env
    - sshd_use_directory_configuration
    - sshd_disable_empty_passwords
    - file_permissions_var_log
    - dir_permissions_binary_dirs
    - file_permissions_binary_dirs
    - file_permissions_system_journal
    - file_permissions_journalctl

Wait, no documentation? Okey… I think there are more pressing unanswered questions, but sure. There’s no documentation for this profile. I just scrambled it together from more or less random pieces I found in other profiles. All this means is that when we do a build we have to supply the --debug flag.

The rules mentioned in “selections” can be inspected. For instance accounts_umask_root can be found defined in (drawing in breath) linux_os/guide/system/accounts/accounts-session/user_umask/accounts_umask_root (breathes heavily).

To build this, one executes:

cjp@fedora$ ./build_product --debug ubuntu2404

This generates lots of output about all the steps but if everything completes it’s not instructive(but it something I had to dig into when things didn’t work).

But this generates a DS(data-stream) that we can use:

cjp@fedora$ oscap-ssh root@template.incandescent.tech 22 xccdf eval --fetch-remote-resources --profile xccdf_org.ssgproject.content_profile_joholo_baseline --results-arf arf_$(date +%s).xml --report report_$(date +%s).html build/ssg-ubuntu2404-ds.xml

Which initially shows that we have some things to fix:

So let’s try to fix this!

Remediation

Most rules (but not all) offer a semi-automatic remeditation to be performed. In the most recent case I did this:

oscap-ssh root@192.168.2.115 22 xccdf generate fix --fetch-remote-resources --profile xccdf_org.ssgproject.content_profile_joholo_experimental --template urn:xccdf:fix:script:ansible  build/ssg-ubuntu2404-ds.xml | tee fix_experimental_hardened.yml

Now, you need to modify the oscap-ssh binary as I described last year(presented below as diff format):

161a162,163
elif [ "$1 $2" == "xccdf generate" ]; then
    true

The produced playbook needs to be slightly edited to make it valid YAML but otherwise it’s just something to try running with Ansible as per usual. Sometimes the execution stops because… well… Sometimes a remeditation is a bit buggy and tries to introduce a key exchange algorithm for SSHD that isn’t valid, but you can just comment out the stuff already done to speed things along for subsequent executions. In the end you end up with something correct:

Modifications

So I don’t order off the menu in these situations. I don’t have to adhere to FIPS and I don’t want to keep root from logging in directly, only ensure that we don’t allow passwords for logging in as root. For instance I don’t care much for AIDE because as far as I can tell it only acts as a tripwire-defence to tell you if files have changed. OSSEC does that and various other things. So I need to create my own rules. For instance, is ossec-hids-agent installed? In linux_os/guide/system/software/integrity/software-integrity/ossec/server_ip_in_ossec_conf/rule.yml:

documentation_complete: false


title: 'OSSEC clients should report to a given OSSEC server by IP'

description: |-
    OSSEC clients should report to a given OSSEC server by IP.

rationale: |-
    It is the role of the OSSEC server to decide on active rewsponses
    which may be relevant to perform on _all_ servers even if the cause
    is found only on one server.

severity: medium

This is just a sort of wrapper to linux_os/guide/system/software/integrity/software-integrity/ossec/server_ip_in_ossec_conf/oval/shared.xml:

<def-group>
  <definition class="compliance" id="server_ip_in_ossec_conf" version="1">
    {{{ oval_metadata("Check if OSSEC is set to communicate with correct server", rule_title="server_ip_in_ossec_conf") }}}
  <criteria operator="AND">
    <criterion comment="Ensure server-ip is set correctly" test_ref="test_server_ip_set_value" />
  </criteria>
  </definition>

  <ind:xmlfilecontent_test check="all" comment="Server IP is correctly defined for OSSEC" id="test_server_ip_set_value" version="1">
    <ind:object object_ref="object_ossec_conf" />
    <ind:state state_ref="state_ossec_conf" />
  </ind:xmlfilecontent_test>

  <ind:xmlfilecontent_object id="object_ossec_conf" version="1">
    <ind:filepath>/var/ossec/etc/ossec.conf</ind:filepath>
    <ind:xpath>/ossec_config/client/server-ip/text()</ind:xpath>
  </ind:xmlfilecontent_object>

  <ind:xmlfilecontent_state id="state_ossec_conf" version="1">
    <ind:value_of datatype="string" entity_check="at least one">192.168.2.120</ind:value_of>
  </ind:xmlfilecontent_state>

</def-group>

This might look fairly straight forward but this is not brilliantly documented and I ended up reading some C-code and introducing my own debug-statements in /usr/lib64/python3.13/xml/etree/ElementTree.py to figure it out.

I finally got things to build and then it was “only” solving the issue of oscap not actually comparing things to the right values:

It took a few more tries to get it right:

linux_os/guide/system/network/network-firewalld/ruleset_modifications/configure_firewalld_rate_limiting/oval/shared.xml was a gift from the gods in trying to get this to work.

Yes, yes… I am aware I hard-coded the IP-address in the linux_os-definition and it should be a variable. I’ll fix that. Eventually… The OSSEC config-file is in XML so this ought to allow me to enforce various requirements for the ossec client and server.

The hardened profile tested above is this:

documentation_complete: false

title: Johan experimental hardened profile

description: |-
    This profile is meant for servers reachable from the internet and therefore
    needs hardering.

selections:
    - accounts_no_uid_except_zero
    - accounts_root_gid_zero
    - accounts_root_path_dirs_no_write
    - accounts_password_pam_pwquality_enabled
    - accounts_umask_etc_bashrc
    - accounts_umask_etc_login_defs
    - accounts_umask_etc_profile
    - accounts_umask_root
    - accounts_user_dot_group_ownership
    - accounts_user_dot_user_ownership
    - accounts_user_interactive_home_directory_exists
    - account_unique_id
    - account_unique_name
    - accounts_password_last_change_is_in_past
    - audit_sudo_log_events
    - audit_rules_sudoers
    - audit_rules_sudoers_d
    - audit_rules_dac_modification_chmod
    - audit_rules_dac_modification_chown
    - audit_rules_dac_modification_fchmod
    - audit_rules_dac_modification_fchmodat
    - audit_rules_dac_modification_fchown
    - audit_rules_dac_modification_fchownat
    - audit_rules_dac_modification_fremovexattr
    - audit_rules_dac_modification_fsetxattr
    - audit_rules_dac_modification_lchown
    - audit_rules_dac_modification_lremovexattr
    - audit_rules_dac_modification_lsetxattr
    - audit_rules_dac_modification_removexattr
    - audit_rules_dac_modification_setxattr
    - audit_rules_execution_chacl
    - audit_rules_execution_chcon
    - audit_rules_execution_setfacl
    - audit_rules_file_deletion_events_rename
    - audit_rules_file_deletion_events_renameat
    - audit_rules_file_deletion_events_unlink
    - audit_rules_file_deletion_events_unlinkat
    - audit_rules_immutable
    - audit_rules_kernel_module_loading_delete
    - audit_rules_kernel_module_loading_init
    - audit_rules_login_events_faillock
    - audit_rules_login_events_lastlog
    - audit_rules_mac_modification_etc_apparmor
    - audit_rules_mac_modification_etc_apparmor_d
    - audit_rules_media_export
    - audit_rules_networkconfig_modification
    - audit_rules_privileged_commands
    - audit_rules_privileged_commands_insmod
    - audit_rules_privileged_commands_modprobe
    - audit_rules_privileged_commands_rmmod
    - audit_rules_privileged_commands_usermod
    - audit_rules_session_events
    - audit_rules_suid_privilege_function
    - audit_rules_sysadmin_actions
    - audit_rules_time_adjtimex
    - audit_rules_time_clock_settime
    - audit_rules_time_settimeofday
    - audit_rules_time_watch_localtime
    - audit_rules_unsuccessful_file_modification_creat
    - audit_rules_unsuccessful_file_modification_ftruncate
    - audit_rules_unsuccessful_file_modification_open
    - audit_rules_unsuccessful_file_modification_openat
    - audit_rules_unsuccessful_file_modification_truncate
    - audit_rules_usergroup_modification_group
    - audit_rules_usergroup_modification_gshadow
    - audit_rules_usergroup_modification_nsswitch_conf
    - audit_rules_usergroup_modification_opasswd
    - audit_rules_usergroup_modification_pam_conf
    - audit_rules_usergroup_modification_pamd
    - audit_rules_usergroup_modification_passwd
    - audit_rules_usergroup_modification_shadow
    - chronyd_configure_pool_and_server
    - chronyd_run_as_chrony_user
    - disable_host_auth
    - file_owner_etc_group
    - file_owner_etc_gshadow
    - file_owner_etc_issue
    - file_owner_etc_issue_net
    - file_owner_etc_motd
    - file_owner_etc_passwd
    - file_owner_etc_security_opasswd
    - file_owner_etc_security_opasswd_old
    - file_owner_etc_shadow
    - file_owner_etc_shells
    - file_owner_grub2_cfg
    - file_ownership_audit_binaries
    - file_ownership_audit_configuration
    - file_ownership_home_directories
    - file_owner_sshd_config
    - file_permissions_etc_audit_auditd
    - file_permissions_etc_audit_rules
    - file_permissions_etc_audit_rulesd
    - file_permissions_etc_group
    - file_permissions_etc_gshadow
    - file_permissions_etc_issue
    - file_permissions_etc_issue_net
    - file_permissions_etc_motd
    - file_permissions_etc_passwd
    - file_permissions_etc_security_opasswd
    - file_permissions_etc_security_opasswd_old
    - file_permissions_etc_shadow
    - file_permissions_etc_shells
    - file_permissions_grub2_cfg
    - file_permissions_home_directories
    - file_permissions_sshd_config
    - file_permissions_sshd_private_key
    - file_permissions_sshd_pub_key
    - kernel_module_cramfs_disabled
    - kernel_module_dccp_disabled
    - kernel_module_freevxfs_disabled
    - kernel_module_hfs_disabled
    - kernel_module_hfsplus_disabled
    - kernel_module_jffs2_disabled
    - kernel_module_overlayfs_disabled
    - kernel_module_rds_disabled
    - kernel_module_sctp_disabled
    - kernel_module_squashfs_disabled
    - kernel_module_tipc_disabled
    - kernel_module_udf_disabled
    - kernel_module_usb-storage_disabled
    - mount_option_dev_shm_nodev
    - mount_option_dev_shm_noexec
    - mount_option_dev_shm_nosuid
    - mount_option_home_nodev
    - mount_option_home_nosuid
    - mount_option_tmp_nodev
    - mount_option_tmp_noexec
    - mount_option_tmp_nosuid
    - mount_option_var_log_audit_nodev
    - mount_option_var_log_audit_noexec
    - mount_option_var_log_audit_nosuid
    - mount_option_var_log_nodev
    - mount_option_var_log_noexec
    - mount_option_var_log_nosuid
    - mount_option_var_nodev
    - mount_option_var_nosuid
    - mount_option_var_tmp_nodev
    - mount_option_var_tmp_noexec
    - mount_option_var_tmp_nosuid
    - no_rsh_trust_files
    - no_duplicate_uids
    - package_ossec_agent_installed
    - server_ip_in_ossec_conf
    - package_audit_installed
    - partition_for_home
    - partition_for_var
    - partition_for_var_log
    - partition_for_var_log_audit
    - partition_for_var_tmp
    - service_auditd_enabled
    - service_tftp_disabled
    - service_vsftpd_disabled
    - service_xinetd_disabled
    - service_ypserv_disabled
    - sshd_disable_empty_passwords
    - sshd_disable_forwarding
    - sshd_disable_gssapi_auth
    - sshd_disable_rhosts
    - sshd_do_not_permit_user_env
    - sshd_enable_pam
    - sshd_limit_user_access
    - sshd_set_idle_timeout
    - sshd_set_keepalive
    - sshd_set_login_grace_time
    - sshd_set_loglevel_info
    - sshd_set_max_auth_tries
    - sshd_set_max_sessions
    - sshd_set_maxstartups
    - sshd_use_strong_ciphers
    - sshd_use_strong_kex
    - sshd_use_strong_macs
    - sysctl_kernel_randomize_va_space
    - sudo_remove_no_authenticate
    - sudo_require_authentication

This has been slightly modified since I use alloy to feed data to Loki and Mimir(well, it’s currently Cortex metrics but I intended to replace that with Mimir) and some other things that have caused issues when I’ve rolled out these changes.

I would like some rules in place for IPset and iptables rules, but I’ll have to think about to implement those. Ah, content/linux_os/guide/system/network/network-iptables/iptables_ruleset_modifications/set_iptables_default_rule_forward/bash/shared.sh looks like a good lead.

Metrics

OpenSCAP results don’t lend themselves to metrics directly but if you have 500 servers and want to know that things are secured according to your own profile all you really need is to turn each report into a JSON file that is then

oscap-report -f JSON < arf_1751820778.xml > test.json

And then extract how many pass and how many fail you got:

cjp@fedora:~/content$ cat test.json | jq '.rules | to_entries[].value | select(.result=="pass") | .title' | wc -l
97
cjp@fedora:~/content$ cat test.json | jq '.rules | to_entries[].value | select(.result=="fail") | .title' | wc -l
6

These can be added up and you get a metric suitable for Prometheus. If all of a sudden fail goes from 0 to 50, then you have something to fix. You could of course have 500 metrics – well 1000 technically – to see which servers are causing an issue but you should store ARF files anyway because you don’t know ahead of time what you might want to dig out. Me naming ARF-files with just a timestamp is sensible in my test case but it should include hostname as well for production.

Sovereign Debt

Borrowing money

This sounds like the most boring of topics, well if you understand what that means. It’s an old-ish term and the meaning is “Sovereign” as in “a country is a sovereign state” and debt, well that has the same meaning as usual: “money owed”. So this has to do with how independent(sovereign) states borrow money. I would argue that credit default swaps and collateralized debt obligations can be seen as more boring than this topic but it’s not clear cut.

So Sovereign Debt may seem uninteresting because surely countries just borrow money like everyone else? No, no they don’t. Consider what happens if you want to borrow money from a bank.

  1. You’re probably going to have to put up collateral.
  2. The bank is the big player and it has lots of little borrowers.
  3. The bank can foreclose on your loan whenever they want.
  4. The interest rate is variable over time.

Collateral is an asset(a car or a house) that the lender can sell to get back the money you owe them if you don’t pay them. It the first stumbling-block because in a normal bank loan the bank can only take the collateral through the courts. But when the borrower is the state of France, how is a lender supposed to strong-arm the government into paying up? The courts get their authority and funding from the state itself. This is well understood so when sovereign states borrow money they don’t even pretend to put up collateral because everyone understands that it couldn’t be seized anyhow.

  1. No collateral

The other issue is that a state typically needs to borrow more money than any one bank has. And a bank doesn’t want to have one(1) customer and – to make matters worse – have no recourse if that customer doesn’t pay them. Sovereign states therefore tend to borrow money by issuing bonds. Each bond tends to be rather small, maybe some multiple of $1000, or whichever currency the country uses. That because you are bound to have lots of creditors and one giant debtor – the country in question.

  1. The borrower is the big player and there are lots of smaller lenders

To differentiate things even more bonds typically have “maturation date”, which is just the term used for when a bond-holder can claim their money back. So the lender can’t foreclose on the borrower.

  1. No foreclosure

In the scenario a bond is basically a piece of paper with some nominal amount of currency that “it’s worth”, as well as a fixed interest rate.

  1. Fixed interest rate

It doesn’t say who owns the bond because they tend to be the kind which you can sell freely once you buy them so it doesn’t make sense to write some ownership on the paper. Ownership is just handled how things would normally be traded, it’s not reliant on anything being written on it.

Reverse rules

See how that’s kind of the reverse of a loan from a bank? Here the giant is the borrower of money and there are many, many small lenders; not one big lender and lots of small borrowers.

This may seem like the worst idea in the world, lending money without even the pretense of collateral, fixed interest and you have to wait until the bond “matures” to get your money back? Why wouldn’t the country just refuse to pay? Not being willing – or able – to pay the money you owe is referred to as “being in default”(even renegotiating the terms tends to be seen as a “default” technically).

The thing about that is that no one will buy your bonds if you are in default. Why would you? There exist pieces of paper where government Y has pledged to pay the bond holder some money at some date and they haven’t done that in this scenario. Why buy a similar piece of paper from them? For this reason – and a few others – countries really don’t want to default: they want to keep borrowing money.

Just to cover this as well: why not print the money or raise taxes? Printing money if very inflationary, see Zimbabwe for a country that has recently and repeatedly done that anyway and it hasn’t worked out great, as you may have noticed. Taxes? That is one of a state’s magical bullets but voters tend to react negatively when a government raises taxes so that isn’t popular either. Borrowing allows a government to avoid both boosting inflation and popular discontent.

So buying government bonds is actually a pretty safe investment and banks and insurance companies across the world are very keen on buying them. Oh – by the way – I have previously – and will in future – talk about bonds as actual pieces of paper but nowadays they are purely electronic. That doesn’t really affect the dynamics around bonds but if you have a hard time seeing someone carting off a million bonds in a big truck: yes, you’re entirely right, that isn’t done.

Government bonds are considered so safe that they are frequently seen as safer than lending to a bank. In the financial market everything is priced by risk. So in the case of governments bonds with a fixed value it is the interest rate that varies depending on how much safer people view those bonds than a deposit given to a bank. Maybe the bank offers 2% interest but the investor thinks government bonds would be safer so he accepts bonds that only offer 1% interest.

Bank runs

Now for a short-ish digression: bank runs. This isn’t literally about banks running and nowadays it’s not even about people running to the bank because it’s all electronic these days. But the name comes from people back in the day running to the bank to withdraw their money. If one depositor runs to the bank because he suddenly needs money it’s not a problem. The issue is if depositor Z is worried about losing his deposit and figures he will withdraw the money before the bank runs out. Because then every depositor in that bank will do the exact same thing. Why wouldn’t they? If they weren’t concerned that the bank would be unable to redeem all deposits before, they will be now when everyone else is running to withdraw their deposits!

This is a known problem and I think it’s best to explain two terms:

  1. Insolvent
  2. Illiquid

Insolvent is bad. It means you have more debts than assets and so can’t even theoretically pay back the money you owe.

Illiquid however only means that you can’t right now pay people back the money that you owe them. If people just wait patiently, everyone gets their money back.

Banks are rarely insolvent but almost all banks are illiquid. Their depositors can ask for their money back at like 24 hours’ notice but it take them years to turn all collateral and other assets into cash money. So as long as depositors are satisfied that the bank in solvent and don’t care about the fact that they are illiquid: all is good! This is how financial systems are set up to work. It’s not necessarily the only way to have a financial system arranged but it is the most common one. It could be argued that it’s not great that banks can have short-term liabilaties and mostly long-term assets but this is what we’re going with…

This leads to the somewhat unusual situation where what depositors believe is the difference between having a bank run and not having a bank run. If there’s a run on the bank the financial system will collapse because banks will fail to redeem deposits and typically this brings down pension funds and insurance companies and can turn the country’s currency mostly without value.

Most jurisdictions have a formally defined depositor’s insurance. The US is interesting in that the pseudo-private FDIC offers insurance to depositors in participating banks up to something like $250 000. In Europe it’s €100 000 I think. But in practice the insurance is 100% and there’s no upper limit.

In most countries governments don’t say that openly but as we saw with Silicon Valley Bank, the actual depositor-insurance is not capped. If it were then governments would need to sit and watch one bank fall, then another, then another. They would see bank after bank toppling and see it spread to other financial institutions.

So if you’re looking at the risk of a bank not being able to pay back the money you’ve deposited, that requires both the bank and the state itself being bankrupt. Lending money to the state itself is just accepting one of those risks. In Sweden SBAB is basically a bank run by the state and if you lose the money deposited with them, then holders of Swedish government bonds are also going to lose their money. Or to put in another way: SBAB won’t fail to meet it’s obligations as long as the Kingdom of Sweden has a government capable of worrying about the financial system.

Some countries have failed in this regard anyway. Sometimes because they issued bonds in a currency they can’t print – which is unsurprisingly dumb. Sometimes it’s because they are so financially screwed that there’s no point in trying to patch up the veneer of a functioning financial sector. Many countries in this position will only have one lender they can turn to: the International Money Fund. That is why the IMF is known as a Lender of Last Resort. But they are aware that lending to countries that have squandered the money they borrowed from other people, is kind of a risky proposition. So they require very clear reforms and plans for how the money is to be paid back. They catch a lot of flak for that and I argue that they have a Sisyphean job and it’s better to let countries default and clean things up as best they can, but those are just my two cents.

Yield

Anyway, so government bonds are seen as a safer investment than depositing money into a bank. Goverments do sort of pay a premium on interest for their bonds since they don’t offer collateral(because it wouldn’t be believable even if they tried to put something up as collateral) but even with this increased risk they are still seen as a safer investment than depositing money into a bank. A interesting thing does exist when it comes to the whole maturation date of bonds. If the maturation date is 20 years in the future the money with which the bond was bought is locked away for 20 more years. So for 20 years the money can’t be used for some other investment. And maybe the interest rate on normal bank deposits are higher than the interest offered on the bond? For these reasons a bond that stretch further into the future normally have high interest rates, to compensate for the risk of money being locked away for so long at a fixed interest rate. Sometimes this inversions of interest-rates for short-term and long-term bonds isn’t true and economists tends to freak out whenever that happens.

Now for a very relevant issue, that also sounds very boring: yield. Interest rate is whatever is printed on the bond itself and it is calculated against the nominal value of the bond. So let’s say we have a $1000 bond at an interest rate of 10%. That means whoever owns the bond gets $100 a year. Simple enough. But what if someone feels like it’s 50%/50% if they are going to get their money back from the government that issued the bond? They might sell their $1000 bond for $500! At least they have the money in their pocket and don’t worry about if they’re going to get $0 or $1000 back.

But what about the buyer who got the $1000 bond for $500? He still gets $100 a year! Because until an issuer of a bond goes into default the nominal value is claimed to be the true value when calculating interest. So this new owner gets a de facto 20% yield. Imagine now if that same government tries to sell new bonds at 10% interest. No one is going to buy them. All potential buyers will say “We can just buy these older bonds at half price and even though we recognize that it’s like 50%/50% if we end up getting paid in full, we will get 20% yield until then”. So the government can then only sell new bonds if they offer 20% interest.

I’ve described this kind of like an auction and while an electronic auction typically is held when new bonds are being issued, the government doesn’t have to wait until an auction to find out what interest rate they have to offer. They can just look at what the yield is on their older bonds. They aren’t stupid, they understand full well that they can’t offer half the interest rate of what you would actually get if you bought an older bond. So for any country the interest-rate they need to offer for various bonds that mature at various dates into the future is known at every minute at every day by looking at the yield.

Confidence

This can lead to problems. This isn’t unheard of: investor A isn’t sure country Y will be able to pay him back. He sells his bonds for 90% of the nominal value. The yield rises by 10%. Investor B isn’t sure that country Y will be able to pay him back, so he sells his bonds for 80% of the nominal value and the yield rises proportionally. Investor C wasn’t concerned before but now he’s seeing yields that country Y certainly can’t pay so he sells his bonds for 70%. And so on, and so on. All investors lose some amount of money and outside observers will have a hard time seeing a different cause of this financial loss other than the very same investors that took the loss.

This would be considered pathological behavior for an individual but investors in bonds – issued by governments or corporations – are not united, they are usually competitors who don’t trust each other for five cents, and for good reason. This is none the less a concern for countries, they know that enough investors losing confidence in the country’s ability to pay its debts is enough to drive the state into bankruptcy. It doesn’t matter if there is an actual reason for a loss of confidence, the country still ends up bankrupt. So making your ability and willingness to pay back your debts abundantly clear is very necessary for countries.

An objection might arise here: isn’t this undemocratic? Yes. Yes, it is. This whole thing makes whoever has lent the most money to the government most powerful. It’s no longer just “one man->one vote”, it’s also “one bond->indeterminate control over public affairs”. But governments across the world have chosen to make creditors kingmakers. Creditors originally had no say in the matter and it is only by borrowing more and more money that governments have given creditors a position to call the shots.

So if a government wants to take authority away from creditors and give it to the people: they can do so. They just have to pay back the money they owe. I can only think of one country that did that – Romania – and they completely screwed up their economy so it’s hard to hold that up as a glowing example. In general any politician thinking about reducing the country’s public debt imagines what will happen in the next election if they raise taxes by 3% and then they go on to borrow more money and kick the can down the road. Is that good or bad? That is for each voter to decide but this is how things work in most countries.

Macroeconomics

This is a sort of behind-the-scenes aspect of what is going on in the US, France and South Korea. It’s not just “what did the voters demand in the previous election”, it’s also “how do we keep borrowing money”. Liz Truss seems not to have understood that during her time as Prime Minister or after, which is kind of amazing. Even I know “Let’s spend £25 billion and I am not even going to check if someone will lend it to us” is a bad idea.

I may make it sound like Sovereign Debt is bad but how would a bank, an insurance company or a retirement savings company invest their money if they could buy government bonds? By shares from private companies is the typical offered alternative but does $100 million at Conglomco really yield significant returns? A government borrowing money and spending it on serious investments like power plants, rail roads and universities that yield significant returns is a very sensible way for savings to be handled.

A country like Sweden metaphorically burnt its hand on Sovereign Debt so has really low levels of government debt but on the plus-side we don’t have a big bill to pay for interest rates. And we see a lot of other countries in the West have the problem that they now really need to borrow money but they already exhausted the government’s ability to do that by borrowing money to pay for running expenses that they had no business funding with loans.

End-to-end encryption

Soo… End-to-end encryption isn’t having the best of times. It does make it harder for state’s to spy on people which I guess is a ball-ache. Thus a tradeoff it presented: let’s throw cyber-security for law abiding citizens under a bus and in exchange make it more straight forward for law enforcement to target criminals. That’s not a great tradeoff but as much as I’d like to believe that’s the truth, I think even this sub-standard tradeoff is chimerical. I think what is really on the table here is throwing cyber-security for law abiding citizens under a bus and in exchange we make end-to-end encryption less convenient for criminals. And that’s an even worse tradeoff.

I figured this would be an interesting thing to implement – as a proof-of-concept – to see if it end-to-end encryption can be used in a self-hosting system. Now the elephant in the room is S/MIME (or PGP) but that’s awful. We will soon see that I have a very strong stomach for downright obtuse interfaces so if I say S/MIME sucks, that’s pretty damning. So we’re going to try to implement something more user-friendly than that, which isn’t too hard to accomplish.

Server-side

What we have is a GPG-based client and we’re also using GPG on the server end to implement certain operations while the majority of communications are authenticated with symmetric encryption. Creating organizations requires that you provide OpenPGP-signatures that correspond to these super-admins.

@app.route("/<organization_id>", methods=["GET", "POST"])

GET is allowed for users of that organization. Creating users or modifying them require GPG signatures that match what the server recognizes to be administrators in the user’s organization.

@app.route("/<organization_id>/<user_id>", methods=["GET", "POST", "PUT"])

A user can make a GET request of their own data but only admins can perform POST and PUT.

@app.route("/<organization_id>/<user_id>/password", methods=["GET"])

The last use of GPG-signatures is when asking for a shared key for the server and the client to use for 24 hours to use symmetric encryption. There the client needs to sign a nonce and if this can be verified by the server the server responds with a shared key encrypted with the user’s public key.

fingerprint = backend.get_fingerprint(organization_id, user_id)
encrypted_key = crypto.encrypt_data(shared_key, fingerprint)

So we have sort of double verification for establishing a mapping from user to shared key.

Asking if there are any new messages or sending one:

@app.route("/<organization_id>/<user_id>/message", methods=["GET", "POST"])

Alongside getting the contents of a message and acknowledging the reception of a message:

@app.route("/<organization_id>/<user_id>/message/<message_id>", methods=["GET", "PUT"])

All use symmetric encryption to generate an HMAC. It’s checked like so:

decoded_signature = utils.decode_data(encoded_signature)
shared_key = valkey_connection.get(f"shared_key_{organization_id}_{user_id}")
verified = crypto.verify_hmac(shared_key=shared_key,data=str(nonce),signature=decoded_signature)

Before this we check for nonces being monotonically increasing which is a requirement. Consider if the communication happens in clear-text or you use Cloudflare or something and don’t trust that provider. The worst thing they can do is retransmit an HTTP-request and this doesn’t work so well because the nonce used for each request has to be monotonically increasing. So a request with a duplicate nonce isn’t valid even if the request has a correct signature.

What then if we both have a failure of the TLS/tunneling process and the nonce-memory server-side fails? Then a retransmission is possible! But the most you can learn from that is what someone’s encrypted message is, which isn’t very helpful. Also, that is what you can get from just the TLS failure. This is part of why the server isn’t something that needs trusting. It only ever stores UUIDs and various OpenPGP blobs, like signatures, keys and encrypted blobs.

So while TLS and a requirement for nonces to be monotonically increasing leaves an adversary trying to do mischief with a very narrow opening, even if those protections happen to fail in a way that lines up for a hacker, they could at most get their hands on the encrypted contents of a single messages or ask that idempotent operations be performed again.

Finally we check if nonces refer to a time at most 30 seconds ahead or 30 seconds behind what the server considers to be “now”. A window for malicious actions is very narrow and require multiple failures to line up in just the right way, and it gains you nothing.

Note: I don’t like making user interfaces and I’m bad at it – which is kind of a fortunate confluence of events – and that leaves us with no user interface for me to show. However, I argue that an interface would be stringent about anything coming from the server. Basically all users and keys are stored locally and any change proposed by the server is checked against existing keys. So even if someone gets control over a server and they try to change a bunch of keys for various users… they would get nowhere as all clients would balk at the notion of changes being performed without signatures matching the real – and previously established – administrators.

Oh, one thing I did check in terms of client software is that we can use Yubikeys just fine with this setup. Python-code has no idea how GPG handles signing and decrypting and using GPG already set up to use a Yubikey for OpenPGP operations worked just fine, it was plug-n’-play.

Two-man rule

This system implements a variant of the two-man rule. It’s basically a rule to prevent people from using nuclear warheads wrong, which is a reasonable things to want to prevent. A single person is hard to trust but two people? Everything from mental illness to substance abuse to corruption becomes less of a danger when the two people are involved. What use is there to one guard being suicidal and the other intent on stealing the warhead? You would need two people swayed and in the same way. It’s not perfect but the requirement to have at least two people around a nuclear warhead is an improvement.

There are two super-admins defined and both need to sign a organization id to create a new organization. An organization is created with just one admin so the code for perform “regular admin actions” looks like this:

admin_count = backend.get_admin_count(organization_id)
if (admin_count == 1 and good_signatures == 1) or (
    admin_count > 1 and good_signatures > 1
    ):
          <code for making the requested change>

I could write that more concisely(probably?) but I find value in the logic being overt.

Scaling(1)

So what is the capacity of a self-hosted end-to-end encryption system? I am currently running the server-side stuff on a single node with 2 cores and 8 GB’s of RAM. We have unicorn with 4 workers running the business logic and an instance of Valkey as a caching layer and a MariaDB instance for persistence. That is currently yielding about 50 new messages per second and a similar number of checks for if there are new messages for a user, each second. So that’s going to serve organizations up to maybe a hundred users counting conservatively.

Y-axis shows count of operation type

We max out at almost 250 operations per second but this puts heavy load on the node and isn’t steady-state.

Y-axis shows sum of duration of operation type

We can see that POSTs of new messages took quite a lot of time when seeing this burst in the beginning. (With multiple concurrent processes sending traffic more than 1 second of duration per second isn’t weird)

The long tail is just because one of the replayed logs is sending more than 10 000 messages in total, so it takes a while. This however doesn’t even make the VirtualBox VM from which i run these tests sweat even though it’s three processes in parallel making requests against the server.

This is good(and lead me to declare myself a legend) because I want to be able to test scaling this up further. A single node deployment is just a benchmark to compare other deployments to. If this was production stuff it would make sense to just add more CPUs and RAM to the one node rather than scale out but where’s the fun in that?

Scaling(2)

Oh, why use Valkey? It’s not so much to leverage the fast access times as it’s about reducing the traffic that goes to the persistence layer. Ephemeral chunks of data don’t need to be stored persistently so… let’s not.

Next we’ll try having gunicorn on a business-logic node by itself and let MariaDB and Valkey run on a separate node. We ought to incur some penalties by having traffic go over the network but we will have twice as many cores and twice as much RAM. Oh, I should probably get Grafana running so I can monitor these nodes to visualize the load. Me running top in the terminal isn’t conducive to me showing the load and CPU usage.

[Several hours later, only some of which was spent on this stuff]

There, now Prometheus and Grafana is ready and we can show load:

Now, this is without an indices so I’ll run this again with those in place. Okey, this is weird. So I defined some indices in the code and… it worked. When you write SQL you need to expect that a few passes are necessary to make everything fall into place. I had to run “SHOW INDEX FOR messages;” to see if they were actually there are it seems like they are. Weird…

Well, anyway: the load goes up to 1.6 it seems now with the indices in place. I had expected a bigger change given the introduction of indices. I had better run slow query log. No, seems fine. I checked by issuing a query that I knew couldn’t use any index and it showed up in the slow query log with SET GLOBAL log_queries_not_using_indexes=ON;

Anyway, let’s look at the throughput. Oh, wow. So that boosted throughput a bit:

Most notably it’s significantly shorter than before. As predicted this is fairly clear when looking at POST message:

Okey then, I’ll use the version with indices when I proceed. So it’s the business logic that needs the most resources. I’ll create two more business logic nodes to see if that is enough to saturate the database node, but I suspect I need to increase the amount of traffic from the client side to reach that goal.

Yeah, I need to generate more traffic because the database node isn’t struggling with four independent streams.

This is with the lines stacked so the total load against three business logic nodes and a database node is just 1. And the total amount of traffic is substantial:

And new messages are processed at a rate of more than 200 per second.

Let’s see what the duration is.

Yeah, pretty clear how we’re limited by the clients not having time to send more traffic. I hope to be able to avoid making the dumb client asynchronous because I’m not overly familiar with async in Python, or any language really. No… I think I’ll try removing the indices to see if that allows me to put more strain on MariaDB because even with like 8 processes sending traffic and the business logic nodes struggling the database node isn’t even approaching a load of 1.

No more indices

Ah, yes, now the persistence node is considerably more strained so I can now have two more persistence nodes that are read-only replicas of the primary MariaDB host.

I went ahead and made an async dumb client. I got quite a bunch of failures before saying that the script shouldn’t pipeline the first few dozen requests or the client will fail to add initial users and then everything else fails as a consequence. Still not a lot of load on the database with the indices back in place(I did that during debugging the asynchronous client) so I’ll try remove one of two and see if I can get a reasonable database-load. I may have have screwed myself somewhat with using Valkey as it sees approximately the same number of operations per second as MariaDB. So I could have seen double the load on the MariaDB-node even with indices in place. Oh well.

First async simulation after a few earlier debug runs

Seems I have an issue with the client side records that I use to collate operations. I’ll see after the next simulation run is over. The logs are written at the end.

Backends

I argue that the business logic is already horizontally scalable. It’s not that we can’t cause issues by issuing 3 000 operations to 30 different business logic nodes that all try to get a shared password for one user. Well in reality the monotonically increasing nonce requirement will make that fall at the second hurdle, but my point is that the business logic scaling out horizontally can be undermined by crafting traffic carefully using credentials that allow you to perform operations in the system, but that’s not really what we’re trying to avoid. We could add rate-limiting for IP-addresses and have various guards in place to keep bots from causing issues if that was our concern.

But if we try to scale out MariaDB to 30 nodes that’s not going to work even with us trying to give that setup the best possible chances of success. MariaDB is a traditional RDBMS, it’s only going to handle a single primary and a small number of pure read replicas. So as it stands MariaDB is the bottleneck that puts an upper limit on how much traffic a cluster can handle. Sure, most work is done by the business logic and that scales quite well horizontally but eventually MariaDB will set the upper limit.

So I intend to implement a ScyllaDB backend and maybe even a pure Valkey backend. The former isn’t too hard, I made an early development version with Amazon Web Services DynamoDB as a backend. A pure Valkey backend is harder because even though ScyllaDB is a key-value database with lots of restrictions compared to an RDBMS like MariaDB, Valkey is pure a key-value store. Valkey expects one key and will give you one value. That value can be a list or an object attribute(called hashes in Valkey) but you can see the limitation I think.

But I have to get the asynchronous benchmarking software to work more correctly for it to be feasible for me to continue that process.

Partial conclusions

I argue that while this implementation is kind of crap and under no circumstances should be used for production deployments, the idea of having

  1. end-to-end encrypted communication
  2. a client running on an actual computer
  3. a Yubikey to hold your private key very safe

translates to something a lot of more secure than running WhatsApp on your smartphone. I’m not throwing shade on WhatsApp, but Samsung controls what runs on my smartphone and I wouldn’t trust them to handle sensitive data. With data exchanged using end-to-end encryption, a signature on a piece of paper won’t do much to help law enforcement, so hacking or adding spyware through the manufacturer becomes the only halfway realistic method to get at the data. And that’s the the last two items become kind of important.

Out-of-Order problem

I realized I made a mistake in how I thought about time. Now there are many ways in which we as computer people have a wrong understanding of time, as Rethinking Time in Distributed Systems discusses(originally seen on EE380 Computer Systems Colloquium available via iTunes U, because I liked that lecture before everyone else thought it was cool) so this shouldn’t be entirely surprising. This is how I thought about timestamps:

Here we see the time in the leftmost column, think of it like Unix time. The number of the three columns to the right indicate the message IDs received at each server. The last three shows which message IDs the server would return if the user asked for messages after t=15. So far, so good.

Next, a message 35 showed up at t=16 and all three servers reflect this correctly. Still no problem.

Now we have a problem! Server 1 received a message with ID 17(I know message ID is 17 and t=17 but this was a coincidence and not intended, so there is no real connection between message ID and timestamp, in the example or in reality) and if anyone asks that particular server than all is well but the other two servers have no knowledge of this “message 17”. So they will respond to queries for “new” messages as if though server 1 hadn’t received anything. It’s not their fault, it’s server 1 that isn’t propagating this information as it should.

Now a new messag with ID 28 has shown up at server 2 and all three servers see this correctly, but message 17 still hasn’t registered at server 2 and 3! So when the user asks server 2 “Are there any new messages” they get an incomplete list and what is worse, now the user thinks it has all messages received up to and including t=18. Why would the user think this? It received information about message 28 and it was marked t=18.

Now finally the information about message 17 has propagated to servers 2 and 3. But this isn’t much help if the user asks for all messages received after t=18. Why would server 2 include this old message if the user asks for things strictly after t=18?

So this problem of out-of-order delivery means that using wall clock time to say “I only want new messages” isn’t viable. We’re at risk of losing messages and that’s a cardinal sin in any kind of messaging protocol.

Solving the out-of-order problem

So what is the solution? I have thought about many possible solutions.

  • A constantly updating CRC checksum between the server and the client to catch aberrations? No, very unwieldy.
  • How about looking at the acknowledged attribute of a message? No, that would mean we can’t support multiple clients and we shouldn’t paint ourselves into that corner.
  • How about letting the server have a concept of a “thread of discussion” and let messages have a strict numerical ordering, kind of like in TCP? No, threads are client side things, we don’t want to tailor the server side stuff for that use case.

This is what I have concluded: we need the server to have a concept of a “client”, meaning a access point used by a user – as recognized by the system. Each client corresponds to a sequence of message IDs that have been fetched already. So when a client asks for “new” messages the server can look at all relevant message IDs, subtract any that have already been fetched and return the final assortment to the client.

So we distinguish between a message being acknowledged which means the recipient has told whoever they are talking to that they have the message and can’t refute that they have, and a message being fetched which means that a client has downloaded it. The former is something that two users are going to be interested in but the server doesn’t care. It uses a symmetric password to make sure clients are who they claim to be so there is little point in them checking the verification signature. Similarly a user cares little that “some clients” have downloaded a message from “the server”, even though this is highly relevant to both the server and the client.

This is true but I should also recognize that not having the server do more public key operations is a way to let the server handle more traffic. So even if I saw some benefit to verifying verification signatures on the server I probably wouldn’t because it would eat more CPU than it was worth.

Naïvely, the algorithm can be seen as this:

  • Get all message IDs for the requesting user
  • Get a list of all acknowledged message IDs for the requesting user
  • Subtract the acknowledged message IDs from the list of all message IDs
  • Return the final result

This is kind of pain though. Imagine if we hold messages for two weeks and we have several hundred thousands of messages? This would quickly end up being very inefficient. This means we now have to ask ourselves when we can stop worrying about the out-of-order problem.

In theory there is no upper limit to eventual consistency delays or replication lag or concurrency weirdness but in practice a messaging system with delays exceeding 30 seconds will not be fit for purpose. Users are going to be negatively affected. So if we set the upper limit to 5 minutes we’re not strictly speaking making sure we avoid all possible issues, but in practice we will encounter several other issues before the time=500 seconds limit becomes relevant. So I distinguish messages for a user as either being in the “consistent” block or the “inconsistent” block.

The inconsistent block is the last five minutes worth of messages. The consistent block is all the messages old than that. So we basically assume that the problem of out-of-order delivery as described above can only happen in this 5 minute period. Do we assume that all messages in the consistent block have been fetched? No, not at all. To figure out which messages are “new” to a client we can use the algorithm shown above if push comes to shove, but we will swiftly want to establish a “last known good” timestamp for a client.

I’ll try to create a chart of that:

Here we imagine a message has arrived every 60 seconds and we see a list of which have been fetched by three different clients the user has. Here we establish a “last known good” value for client A as… time=1020

Why not 1500? Because the messages after 1020 are in the inconsistent range where we can’t rule out out-of-order delivery and have to go through the hassle of comparing the list of candidate message IDs to the list of fetched messages for client A, lest we miss one due to eventual consistency or whatever.

Client B? The last known good value is time=900. After time=900 we have the first unacknowledged message so henceforth we have to ask the backend “hey, give me all messages after time=900” and then check them against the list of fetched messages. Sure, there’s a bunch of messages recently that have been acknowledged but a request for “new” messages have to include the unfetched messages from earlier.

Client C is fairly simple, it hasn’t kept up with the absolute latest messages but the last known good value is still time=1020 just like client A.

So, for each client we would like a “last known good” value to make fetching new messages more efficient. If no such value exists yet we have to do the hard work involved in establishing this value as outlined above. In practice I don’t think “set A minus set B” where A and B are a few hundred thousand UUIDs is a terribly taxing operation for a computer to perform but it will be a very rare operation using the above decribed method. Once the LKG value is established we can fetch messages and there will only be a 5 minute overhead where we are meticulous to avoid out-of-order issues causing trouble.

We should limit how many clients are user can have. I think 5 is reasonable but making this value configurable to that the weird customer that wants 70 clients of one user for some reason can have that. I figure that the information about a client is miniscule, with just an LKG value really. The bulk of the data is the corresponding list of fetched messages which can range in the multiple of megabytes.

I am thinking about this as a ScyllaDB+Valkey setup where the LKG value is stored in Valkey(because it may be frequently updated but it can be derived from persistent data if Valkey has an aneurysm all of a sudden) and we can simply have the “fetched” table use “organization_id#user_id#client_id” as a partition key and add new entries every time the client fetches a message. I see no real need for a clustering key here since we are using this precisely because we don’t trust wall clock times.

Groupthink

Sometimes people have taken Ecstacy and become quite hot. This is not extraordinary but sometimes they have also suffered a dysfunction of their bodily feedback so they can’t sense when they’re too cold or had too much water. This is a fairly small proportion of all ecstacy users but it has happened. And they have had tap-water by the gallon. Since tap-water has a lower salt content than existing fluids in the body, this causes swelling of tissue. This is fine when it’s your arm or something but guess how much space your brain has to swell? Yes: None! So these people have had pressure on their brain build up and supress their breathing so they die.

We normally attribute this to ecstacy and you aren’t well placed to complain about this; you took a bunch of MDMA and your body malfunctioned… How is that that not in line with projections? But technically these people died from tap-water poisoning. So we can’t say that tap-water is 100% safe, merely 99,9999% safe. Nothing is 100% safe. So can we find a handful of examples of people suffering severe allergic reactions to a Covid-19 vaccine? Sure we can. Vaccines aren’t approved if there are 0 side-effects, merely if the expected side-effects are eclipsed by the positive effects. So finding a handful of examples of Y where we see negative outcomes, we can’t assume that Y is bad. We can’t assume Y is good either, we actually have to use our brains a bit and think farther than the reach of our nose.

So what is groupthink? I would define it as a phenomenon where a group agrees on an idea and see this idea as integral to what they’re doing and reject contradicting evidence. And I can cite several instances of this not working out so well:

Sometimes planes crash and lots of people die.

Sometimes a bridge collapses and some people die.

Sometimes an organization tries to switch to new software for medical use and it doesn’t go so well.

But as established earlier, we can’t extrapolate from those situations and conclude that groupthink as a whole is bad. So is groupthink good? Well, I don’t think that’s entirely correct but it’s kind of complicated.

Most organizations in the world foster groupthink, but using different words:

You need to be a team player. Some people are just poindexters who try to make a mountain out of a mole-hill. We all have to pull things in the same direction!

And this isn’t entirely wrong. Show me the company that has persisted for decades without underscoring how people need to be team players or that has people in authority highlighting issues as blockers that need to be fixed before things can progress! Organizations effectively rely on groupthink as a steamroller that smooths out bumps in the road.

Now for an aside: the Challenger accident. If you weren’t around at the time, the Challenger was a space shuttle used by the US in the 80’s and it exploded during launch, killing all aboard. It wasn’t great… The issue came from something as weird as an O-ring used to make sure the many segments of a solid rocket booster didn’t leak. With the solid rocket boosters containing – yes, you got it – solid rocket fuel this task of maintaining a seal was kind of important. The contractor Morton-Thiokol said to NASA before the launch:

Hey, these O-rings don’t handle freezing temperatures too well and these boosters have gone through some sub-zero temperatures. We should dismantle the boosters and replace the O-rings.

NASA said that if the contractor insisted on scrubbing the launch, NASA wouldn’t do business with them again. Morton-Thiokol withdrew their complaint, the shuttle took off and a handful of people died. Now, why would you spend so much money of safety and quality control and then threaten contractors who raise safety-concerns with losing NASA as a customer? Surely you could just not spend all that money on quality to begin with, right? But I wonder how many other contractors brought similar concerns to NASA, NASA told them to withdraw their objections or lose NASA as a customer and then nothing bad happened? It’s all well and good to imagine how this one instance of incompetence was the only problem, but these were senior managers in NASA. They were not promoted by accident. It’s a bit naive to think that they operated this way behind the organization’s back in one out-of-character moment.

Okey, so where are we? Well, we can find some clear examples where groupthink has been pretty terrible but we’ve also seen that groupthink isn’t some insidious force that worms its way into organizations to bring them down, rather organizations foster groupthink in the pretty sensible pursuit of team-work. So can we foster team-work without going over into groupthink? I don’t think that’s realistic for most situations. Most organizations want some measure of groupthink as a battering ram to get rid of obstacles. They don’t want things to get out of hand to where the group ignores reality and the organization suffers a massive debacle that costs them hundreds of millions of dollars, but they do want some groupthink… And I think this is a bigger problem than people recognize: it’s not clear ahead of time when an organization is thundering ahead in spite of small issues and when they are ignoring reality as a whole. It might sound straight forward to separate those two things but look back in time and show me where people have some Oracle-level precognition when there is trouble afoot.

My recommendation would be that if you do things that aren’t life-critical, you should just try to achieve whatever is expected of you. If you mess up, chalk it up to $100 million learning experience and move on. If you do things that are life-critical: err on the side of caution. Because if you mess up, you would be lucky to continue operating as an organization after that. But this is in my view an intractable problem. Like how we accept that computational complexity O(n)=n² is not going to scale well. We realize that isn’t some problem to be solved as is. We recognize that rather than somehow make O(n)=n² fine and dandy, we need to figure out how to do the same task with O(n)=log(n) (well, hopefully). So where does promoting team-work veer over into groupthink and where does groupthink veer into “we’re about to fail massively but we’re just going to ignore that”? There are no clear answers, no fixed tests. No neat questionnaires that you can have people fill out to tell you if you about to have a big problem. You kind of have to play with fire and figuring out when things have gone too far is hard.

But as it stands the Region of Västra-Götaland is treating the Millennium failure as “oops, all berries” which doesn’t bode well if they are going to right that ship. Blaming civil servants for engaging in groupthink in a staggering manner and trying to pass all blame of on them is not convincing.

South Korea

What… the hell are you doing? This should all have been handled nicely behind closed doors. The military just needed to explain things to the president:


You’re thinking about declaring Martial Law. We have known that for a few days. If you do declare Martial Law we in the military will do two things:

  1. Pretend like this is news to us and we had absolutely no idea you were going to declare Martial Law.
  2. Act as if though we had no reason to doubt the president’s word about there being a clear military threat.

Then after a few hours we would say “Hey, enough time has passed for us to stop pretending like the declaration of Martial Law was legitimate”. At that point we will tell you – in private – to rescind your declaration. If you don’t, we will make a public statement that the military considers the declaration of Martial Law to be invalid. The only reason we won’t do this immediately is because the military must be seen to respond resolutely to the declaration of Martial Law. We have to spend a few hours before we can pull the plug on Martial Law and say “There’s no change to the military threats against our nation, this is just some politician who doesn’t like losing his majority in the legislative assembly”.


A sensible politician would then draw the conclusion that he can’t solve the problem of “no longer having popular support” with “Martial Law”, something which he really should have been able to figure out on his own but at the very least the military should have explained it to him.

South Korea is making things worse all the time with the PPP saying that they won’t support impeachment of the president because “he apologized” before deciding that the did support impeachment. Not sure why an apology is a non-zero issue to be honest, normally an attempted coup d’état is dealt with more forcefully. Not staffing the Supreme Court so that they won’t have the necessary quorum to deliver a finding in the impeachment… At some point, will you stop shooting yourself in the foot? Is that even a remote possibility?

The military seems to be unsure of which side to take in this conflict. I would argue that the Constitution is a good bet here. Not because it’s the unalterable word of God, but at least it’s more sensible than many other characters involved in this drama. I don’t quite understand why civil servants are prosecuted alongside the president. How is playing along with the declaration of Martial Law(until the president “somehow” rescinded it) not entirely in line with their obligations?

Since sensible politicians seem to have gone missing in South Korea of late, let me explain things: South Korea is very dependent on the rest of the western world. It exports stuff to the rest of the world, the West in particular. It also needs to buy a lot from other countries. It stands to benefit by seeming stable and orderly. Now it’s unclear who is in charge, if the constitution is upheld, who is on the Supreme Court, if the military and the police pursue the same goals and so on. You see how that isn’t conducive to being seen as a reliable business-partner to whom you may lend money?

Balatro

I play a lot of Balatro and I’ve started to realize that some Joker-combinations are desirable:

  • Mystic Summit: +15 Mult when there are 0 discards left
  • Splash: Every played card counts in scoring
  • Green Joker: +1 Mult per played hand, -1 Mult per discard
  • Burglar: When Blind is selected, gain 3 hands and lose all discard

That leaves one open slot and Bull(+2 chips per $1 you have) is pretty good. Speaking of which, a second setup which would be good is to buy the vouchers that increase how much interest you can earn(Seed Money and Money Tree ) and these Jokers:

  • Bull: +2 chips per $1 you have
  • Rocket: Earn $1 at the end of each run, payout increases by $2 when Boss Blind is defeated
  • Delayed Gratification: earn $2 per discard if no discard are used by end of the round
  • To The Moon: Earn an extra $1 of interest for each $5 you have at the end of the round
  • Golden Joker: Earn $4 at the of each round

Phrases that do more harm than good

Populists

Why do people keep referring to whoever they don’t like as “populists”? Basically that term is used like this:

Populism: democracy that I don’t like

Democracy: democracy that I like.

So typically when someone tars someone with the populist brush they are basically saying “I don’t like them”. This typically isn’t a surprise. It tends to be fairly obvious that the author doesn’t like Donald Trump or Boris Johnson but “I don’t like them” isn’t particularly convincing. Both those gentlemen have enacted utterly idiotic policies but these can be addressed directly. Falling back on calling them populists isn’t doing anyone any good. Maybe people who also didn’t like them thinks that “populist” is a very clever accusation to level against them but I don’t see how it is important to curry favor with that demographic.

Some argue that they use “populist” in a very clear way, though exactly which way tends to differ from people to people. A popular(if you pardon the pun) definition is that “populism is about Us and Them.” I challenge you to name a party that doesn’t argue that they are environmentally sound and oppose all those polluters out there, or that they represent the hard-working people opposed to those who rely on welfare etc etc. Just because you don’t like how party X chooses which demographic to placate doesn’t make their choice of some demographic to placate radically different.

Maybe “populism” is to propose things that sound good but will turn out poorly? Pandering to some demographic. But that’s just how democracy works. Politicians propose things and some say “Yeah, that sounds good” and some say “No, that’ll never work”. There’s no guarantee that whatever gets the most votes is the better alternative. Democracy is about the majority vote getting their way whether they are right or wrong.

How about demonising the Establishment? This is slightly better because in the most literal interpretation it creates a clear delineation unlike other definitions. But while a small group might literally propose that they are opposed to the Establishment, a lot of parties make the same argument but try to dress it up in different clothes. It’s not the Establishment, it’s the Media… It not the Establishment, it’s Industry.

If you are referring to the old Russian narodniki party then OK, the most accurate translation will have to be “the populists” basically. But trying to leverage the same term to criticise political opponents? That does more harm than good and there are usually actual policies that are ripe for criticism on a more constructive plane.

The Rule of Law

“The rule of law” has been a great way for people to criticize political opponents. For instance France’s criticism against Poland dismissing judges because the Polish state introduced the same age-requirement that already exists in France. Typically people use the phrase “the Rule of Law” to mean “keep things the way I like them”. But at the end of the day someone has to appoint judges. This could be handled entirely within the judiciary but that has obvious democratic problems. There’s no guarantee that the judiciary is in step with the people since there’s no link between electoral outcomes and the judiciary.

I think a semi-reasonable interpretation is that “the Rule of Law” lets the legislature draw up laws and their interpretation but that the executive branch of government can’t directly overrule any verdicts. Note that some would object to the legislature having authority to decide on how laws should be interpreted – and that’s not entirely unreasonable – but it’s a little bit too easy to just plain ignore what the law says if the judiciary is free to interpret things as they wish.

I have long criticized Roe v. Wade because the 14’th amendment doesn’t protect the right to abortion and the Supreme Court was right to overturn it recently. The Supreme Court was if anything several decades late. Abortion rights should have been enshrined in law because it was patently obvious that the 14’th amendment gave no such protection but it was much too easy to hide behind the Supreme Court. In case your wondering, I don’t think abortion rights should be enshrined in the constitution because the constitution of any country is about fundamental rights. Defining that abortion is legal up to week 26 is not suitable for the constitution. A blanket ban or a complete legalisation is more in line with what a constitution defines but even the people on the pro-choice side of the argument don’t think that abortion should be legal in the 7’th month. So it is best expressed in a law that can be updated as it becomes appropriate.

How does this relate to “the Rule of Law”? Well, typically the people who are most opposed to the Supreme Court reversing Roe v. Wade are people who are adament that they are protectors of the Rule of Law while there are others – frequently populists! – who seek to undermine it. But when the Supreme Court rules against them the Rule of Law takes on a different interpretation. We see this in Poland where the new prime minister is trying to reverse what the previous regime introduced but those changes were inshrined in law so any direct dissolution of the state broadcaster for instance isn’t coherent with the Rule of Law.

My point is that the Rule of Law is a lot more complicated than “I like that policy” or “I don’t like that government”. At it’s heart we have to decide how the judicary relates to the government. Should judges be appointed by courts? If so, how do we deal with a judiciary that is at odds with the legislature or the executive branch? Plenty of commenters are keen to rally to defend the judiciary when they are trying to stop changes that have been voted for in a democratic election but that the commenter doesn’t like. We can’t decide the method by which the judiciary is appointed or dismissed based on whether we like change A or change B. We have to decide on how to do this based on more fundamental principles or accountability and then we have to stand up for that decades later. This is the opposite seen among the people who argued that the Supreme Court was right by definition for the past few decades but argued that the Supreme Court was just plain wrong when they overturned Roe v. Wade.

How about the legislature appoints the Supreme Court in the middle of the legislature’s term in office? And then the Supreme Court appoints judges for other “lower” courts? Oh, the US system of Supreme Court justices being appointed for life has to go. I don’t know what they were thinking with that one… The Supreme Court can have a mandate that is as long as that of the legislature, but as mentioned before offset by say two years. And we can stop pretending that somehow “public access television” or “border protection” is immutable and any attempts at changing them is to undermine the Rule of Law? That seems more in line with how grown ups handle these matters.

Liberal democracy

I don’t necessarily object to the phrase “liberal democracy”, but whenever people use it in place of “democracy” it’s kind of bad. Typically the argument is that who goes on over there is illiberal democracy, by populists who undermine the Rule of Law… I argue that whenever we referred to democracy historically, we should keep referring to democracy. For people to suddenly want to do a bait-and-switch in which their interpretation of democracy is liberal democracy with a great many number of preconditions is a detriment to democracy. Because we need to defend democracy as a concept even if people vote for something we consider illiberal. This isn’t some humanitarian élan, it’s just a recognition that we don’t really have a better way of running things than letting the majority decide who runs things and how. Even if they elect Viktor Orbàn that isn’t undemocratic nor is it viable to impose a minority position on the majority.

It’s been much too popular of late to elevate the claims of some group because they have brought a city to a standstill with lots of protesters. Do they command an electoral majority? No, I guess that’s why the people they don’t like are in government. So are we going to let the minority rule because of the protesters they have brought out? What happens when their political opponents bring out just as many protesters are bring the same city to a standstill? Are we going to switch government everty six months?

Let’s affirm that free and fair elections are the hallmark of democracy and people can choose whatever the hell they like, even if we personally might disagree. Similarly sham elections like those in Russia need to be recognized to be blatantly undemocratic independently of what the government calls them. It’s not illiberal democracy, it not democracry, liberal or otherwise.

So let’s stop hiding behind bitesized phrases. “Don’t vote for them, they’re populists!” Or “This government is bad, they aren’t respecting Rule of Law by laying down rules on how the judiciary is staffed”. “We should only accept liberal democracies now!” This isn’t convincing anyone and we’re not addressing the very real issues at hand with these poor attempts at simplification.

Addendum 2024-07-05:

So the US Supreme Court ruled that US presidents have immunity for “presidential acts” but not private ones. The White House denounced it for undermining the rule of law. If the White House had said that they thought that ruling was a bad idea, people would undoubtedly have argued that the White House undermined the rule of law. I argue that they would not have. While it’s something of a gray area, the executive branch are entitled to comment on decisions by the judicial branch. Only if they say that the will do the opposite of what the Supreme Courts says “and they can’t do anything about it”, then the rule of law is undermined.

But for the executive branch of government to criticize the judicial branch for a rendered verdict on the grounds that it undermines the rule of law, that’s an infinite loop of irony! Now I understand the Biden administration’s plight. Donald Trump rejects the results of democratic elections if he loses and he will probably be entirely OK with approving results from undemocratic elections if he wins(if he were to participate in any such elections). Yet Trump is flying high in the opinion polls so openly rejecting democracy – not the highfalutin democratic principles like freedom of speech, just the purely mechanical issue of how elections should be held – does not disqualify you with the voting public. But shooting yourself in the leg like this isn’t helping…

I can’t help but wonder if the White House would have said the same of this verdict if President Biden were under criminal prosecution. Any such prosecution would lack proper substance or justification but I think we all know that prosecutions of presidents past and present don’t need to be legally sound. The Republican party has been trying its best since the last election to prosecute the current president for whatever they can think of.

At the end of the day US presidents and governors of US states have had the power to pardon crimes in their respective jurisdictions since long ago so the old American principle that no one is above the law has been under severe strain for some time.

Addendum 2024-07-29:

The White House wants to impose term limits on Supreme Court Justices. A fine idea! No one should be appointed for life in a democracy. But, this is many decades overdue and launched by a liberal president in regards to a conservative Supreme Court. It would not look like you were undertaking a partisan move to limit the powers of “the other side” if a liberal president tries to impose term limit on a liberal supreme court and vice versa.

The idea of removing immunity from past presidents seems somewhat flawed. I like the approach though, this is how things are supposed to work. If something isn’t to your liking, ask the legislative assembly to fix it, don’t just say that the court is wrong. What is being proposed has approximately 0% chance of passing since it requires all state legislatures to approve it but that’s how the constitution works. It can’t be changed easily. Note that so far this doesn’t seem to infringe on a president’s ability to pardon people:

This No One Is Above the Law Amendment will state that the Constitution does not confer any immunity from federal criminal indictment, trial, conviction, or sentencing by virtue of previously serving as President.

Also, why is this in regards to previously serving as President and not also to serving presidents? Maybe this is a type-o, indeed it wouldn’t be the first on that page:

President Biden believesthat

There should be a another space in there.

Still, all in all this indicates a better grasp of legislative reform. Even when changes aren’t approved at least you have made your position clear and opponents have had to make their positions clear. The only other way to create new rights or obligations is via the Supreme Court who for a long time have been finding things hidden between the lines of existing amendments by “interpreting the constitution in a modern light” as has been euphemistically said. Whether we go back to the Dred Scott case or Roe v. Wade some startling conclusions have been reached by the court on the basis of constitutionality. Neither conservatives nor liberals can rest easy with the Supreme Court wielding the power that they do but seem content to leave things as they are as long as they stand to gain. Somewhat short-sighted…

Progressives

It’s quite the coup to make your political ideology go by the name “progressivism”. But I think it’s pretty clear that you are trying to make whatever you want seem like “progress”. But we don’t know what progress looks like. That’s not a dig at progressivism per se, it’s just an aspect of the human condition that we can only really talk of progress in hindsight, knowing how things worked out. The people in favour of prohibition in the US probably thought they were very progressive but prohibition lasted only a few years. So we can hardly see prohibition as progress. How about Roe v. Wade? Was that progressive? It just got overturned so I fail to see how Roe v. Wade was progress.

Did you like a particular reform? That’s fine! But whether or not it was “progress” is not related to whether or not you liked it. Calling yourself “progressive” does more harm than good because you seem to be laying claim to “progress” as a concept and that you see the future more clearly than other people. Argue for your case but don’t call your standpoint “progressive”.

Clarity of communications

This annoyed me even before I had a stroke: people are not very clear in their communications. Too frequently do people say something like “He gave him a new project and he thought the deadline was too soon”. If we replace the pronous with actual names, would it be like this:

Bob gave Tom a new project and Tom thought the deadline was too soon.

Or like this?

Bob gave Tom a new project and Bob thought the deadline was too soon.

The second example seems to make less sense. Why would Bob think the deadline was too soon if the details of the project was already known to him? But this isn’t made entirely clear in the statement. We’re not well placed to object if the circumstances are such that Tom sets the deadline for the project; the original statement was vague and matches both eventualities. Just because we assumed that the first interpretation was correct doesn’t mean the statement had only one interpretation.

So any use of pronouns needs to be crafted so as to be unambiguous. This is only made more confusing by current tendencies to choose pronouns arbitrarily for oneself as He and She need not translate as the listener expects and is sometimes omitted entirely in favour of other pronouns entirely. In spoken swedish we rarely separate between They(In swedish: De) and Them(In swedish: Dem) and just use the general form “Dom“. But “Dom” can be used many times in a single sentence and refer to a melange of different groups of people or objects, which often doesn’t relay any information and just makes the listener ask: Who did what to whom?

This might be a hard switch from one case to the other, but we can also see quite an issue in the chat-segment of streamers like Joshimuz and English Ben. We might have the streamer ask some question:

Does the Cheetah spawn in San Fiero or just in Las Venturas?

To which the reply is “Yes”. To what exactly are you answering? Asking simple Yes/No questions seems preferable but it isn’t uncommon for multiple question to be asked and for the answer to be Yes or No. I would suggest that a good answer would be something that clarifies what the answer relates to:

Yes, the Cheetah spawns in San Fiero as well.

Note: I don’t know which cars spawn where, I haven’t played GTA: SA for decades. These questions and answers are merely for demonstration.

While it is only in really critical situations where you have to be clear, even in other situations you probably want to get some point across. You are saying things after all… So it makes sense to avoid ambiguity in most circumstances.

The Soviet Internet

I have several times watched an interesting documentary on why the Soviet OGAS never became a reality. It was heavily inspired by what the Americans were doing and their ARPAnet would end up being the internet as we know it today. It aimed to network all factories in the USSR so that the demands of on plant could be more easily linked to the production at another plant. The USSR economy at this time was in dire staits, so why no OGAS?

First of all, in the US the military spearheaded a lot of technology. It was pretty similar in the USSR. The difference was that in the US military technology trickled down to the civilian sector. Not so in the USSR. “The military will never concern themselves with mere civilian issues” was effectively the conclusion drawn by one proponent of OGAS.

Second, it was really expensive. Like, it would have cost more than the clean-up after Chernobyl. The USSR wasn’t a networked or computerized country in general so introducing OGAS would have required a huge investment.

Third, it threatened a lot of bureaucrats whose jobs were endangered by OGAS. So OGAS needed the support of the very people it was bound to replace.

But this is not what I’m curious about. It seems fairly straight forward why OGAS didn’t happen. There were as noted earlier several reasons why it didn’t go anywhere. What I’m curious about is why OGAS was even on the table? This project seems to have been discussed at the highest levels of the USSR before it was mothballed. So improvements to how the economy was organized were discussed? Why then did they not conclude that they needed proper accounting without falsifications? Why didn’t they introduce proper quality control?

Traditionally you try to solve problems from Least Expensive to Most Expensive. Ideally you can pair that with Most Impactful to Least Impactful. OGAS seems very expensive and moderately impactful. At the same time their poor accounting and lack of quality control constituted existential threats to their economy. Now, accounting and quality control isn’t free but I don’t see how the Soviet economy could have survived with them. OGAS however was a solution to a problem that might have been necessary to solve somewhere down the line but there were more pressing issues that cost a lot less right in front of them.

Now, Breznev was notoriously disinterested in corruption so it would have been out of character for him to pursue accounting and quality control as I suggest, but why then even discuss OGAS? If being ideologically correct was more important than anything else, why think in terms of high-tech and networking in the first place?