Social Spin Foam
Power is what an act would do to the distribution over what could be.
A computational model in which social facts of any type sit on the faces of a two-complex, couplings on edges, and the joint compatibility of several couplings on vertices. From it: reconstruction from observation as a weighted ensemble rather than one reconstructed reality, power as the capacity to redistribute weight, and governance decision as a search that returns a set and declines to choose within it. It runs, and it reproduces the model's published results by computing them.
Software, and the paper it answers to
The paper A Social Spin Foam Model for Power Analysis and Governance Decision-Making fixes what kinds of object there are and what the quantities mean. It is the specification. This project is the executable form of it — the representation as data structures, reconstruction and power and search as algorithms, and the paper's propositions as tests that either hold or fail.
That division does real work, because a paper can define quantities it does not compute and state restrictions it cannot enforce on a reader. Both become code here. Where the paper says the type of a fact is not determined by the dimension of the cell carrying it, there is no API through which a type can be read off a dimension. Where it proves that a power measure defined as a difference of weights would report change where none occurred, a test rescales every weight by a random constant and asserts every power value is unchanged.
The principleThe account's discipline is enforced by the type system and the test suite rather than by the reader's goodwill. Every refusal on this page corresponds to a claim that fails if the refusal fails.
pip install -e ".[test,figures]" pytest # 32 passed python demo.py # the whole apparatus in one screen, public API only python figures/make.py # regenerates every figure from the code, seeded
The model, and what each equation costs the implementation
The configuration
Face
a social fact
Of any type. An employment relation, an award decision, a rate of unemployment, a state of emergency — all faces, differing in their type label and in the space their magnitudes live in.
Edge
a coupling
A way two facts combine, constrain, depend on or realise one another: causal, constitutive, normative, ownership, temporal, epistemic, institutional.
Vertex
joint compatibility
How strongly several couplings are jointly instantiated at one place.
figures/make.py. A rule constraining an application and an applicant participating in it are two distinct couplings that meet at one place. A labelled graph or hypergraph on the same three facts asserts one joint coupling among them and loses that distinction — which is what the third dimension is for.The vocabularies 𝒯, 𝒦 and ℛ are supplied by an analyst and replaceable without altering anything downstream. The typing map is unconstrained; every restriction on which facts may occur together is imposed on couplings instead. That is what makes a relation between two relations expressible — R(R₁, R₂) is three faces joined by edges, where confining relations to edges would leave it nowhere to live.
Implementation consequenceNoEventFacesubclass, no dispatch branching on a cell's dimension, no behaviour onFacethat depends on its type — a test walks the syntax tree of every module looking for one. And the core ships no default type system: fixing what can be recorded is an act at the third level of the account's own analysis of power, so a library carrying a default would perform that act silently for everyone who imported it.
Admissibility is the support of the coupling weight
A Boolean type discipline and a non-negative weighting are one structure and not two: the Boolean rule is the indicator of the support, and the weight refines it by grading the admissible cases. The gain is not economy of apparatus. Social couplings are seldom permitted or forbidden outright — more often one is easy to form and another available at cost or under conditions — and a Boolean rule keeps only the extremes.
Implementation consequenceThere is no admissibility table in the codebase.is_admissibleisconfiguration_weight(…) > 0and there is no second route; a test builds a graded weight and its Boolean indicator and asserts they agree on every verdict while only the graded one orders the admissible cases. Caching a Boolean beside the weight is precisely how the two drift until the proposition that unified them stops being true of the code.
The weight of a configuration, and histories
A statement about a configuration is a statement about the totality of ways of arriving at it; a statement about a single social fact is a statement about the totality of configurations in which it occurs. The sum is over non-negative weights — no complex amplitude, no interference, no measurement postulate — and that choice is settled by a criterion rather than by preference: with non-negative weights, removing histories from the sum cannot raise it, so closing off an available way of reaching an outcome never raises the weight of that outcome.
Implementation consequenceA configuration weight is obtained by marginalising the history weight, never computed separately and then permitted to disagree. Monotonicity under path deletion is asserted over 200 randomised removals. And the observation that would overturn the convention ships as a runnable check rather than a caveat: cancellation_diagnostic takes pathway-removal data and reports whether removing an option raised an outcome's frequency. No case examined so far meets it.
Reconstruction is ill posed, so it returns an ensemble
Delete any face outside the image of the compatibility injection and compatibility survives while the penalty strictly falls; distinct unobserved faces give distinct configurations of equal fit and equal penalty. Observation does not determine a unique reconstruction, and a procedure returning one would be breaking ties the evidence leaves untied, with the tie-breaking doing work no observation supports.
Implementation consequenceNo function in the package returns a reconstructed configuration. The reconstruction interface returns anEnsemble, and there is deliberately noargmax,bestormost_likelyon it — a test asserts their absence. What it does have ismarginal, because aggregation across candidates answers a question no single candidate answers.
Power, and a search that returns a set
Types, couplings and the presence of a face are discrete, so a difference replaces a derivative. And a difference of weights is not comparable: rescale every weight by a constant and every difference changes while the normalised distribution does not. Power is therefore the capacity to redistribute weight, and it reports capacity, not exercise — what an available act would do, whether or not it is performed.
An intervention is a list of edits of four kinds — set a face label; add or remove a face; set a coupling weight; alter an admissibility rule — which are exactly the four kinds of act the power analysis distinguishes. The space a governance procedure searches is the space of exercises of power available to the searching party.
Implementation consequenceNo best() and no default weighting of the objectives: for any member of a non-dominated set there is a weighting under which it wins, so a default would make the choice the framework explicitly declines to make. Every objective must declare its neutrality or it will not construct, and the worked design's two stability-like objectives are labelled supplied, not neutral. The word an economist would reach for to name a winner is absent from the package, and a test scans every source file for it.
The worked case
A body awards a scholarship under a published rule. Five facts are observed: two applicants whose recorded attributes agree on every criterion the rule names, the rule itself, and two dated application events — one refused, one awarded. The observed material is inconsistent with itself, so some fact bearing on the outcome is absent from the record. A representation confined to what was observed has nothing to say beyond registering the anomaly.
The last point is the one the procedure is built around, and the program prints it rather than hiding it:
3x weight on the size of the intervention selects 0000 3x weight on auditability of the record selects 0100 3x weight on continuity selects 0000 One set, three weightings, 2 different answers. The selection is determined by the weighting and not by the objectives, so the procedure designates no member and this program prints no recommendation.
Two things the implementation found
Building a thing is what lets it disagree with you. Two disagreements surfaced between the paper's prose and its own numbers, and both are recorded in the test suite rather than smoothed over.
1 · The influence ordering does not, in fact, differ from the ensemble ordering
The paper states that the ordering of the influences “is not the ordering of the ensemble weights”. On its own published numbers the two orderings are the same — budget timing, testimony, panel preference — whether the ensemble is read by single-candidate weight (0.341, 0.290, 0.141) or by marginal (0.519, 0.459, 0.268).
What the numbers do support is the weaker and still substantive claim the surrounding prose makes: the influences are not proportional to the weights. Measured against the leading fact, the panel preference holds 41% of the weight and 55% of the influence. If some third quantity is meant, the account does not say which.
2 · One row of the non-dominated set cannot be reproduced from what the paper publishes
The paper reports the values of Φλ it computed, but not the agreement term ℓ, the coefficient λ or the complexity measure Ω that generate them. Three of the four search rows do not depend on those, and all three reproduce exactly — including the dominated all-four-edits candidate at displacement 1.2393.
The fourth, publish the reasons in full, does depend on ℓ, and no single per-posit penalty reproduces both of the paper's figures for it: the value that lands its opaque weight on 0.258 gives 0.0020 for the displacement rather than 0.0006. The design therefore stipulates the simplest defensible rule — each posited fact absent from the written record disagrees with it by one unit, weighted by the change in confidence — and reports what that gives, 0.2445 and 0.0112. Membership of the non-dominated set is unaffected.
Architecture
Layered, with dependencies running downward only, checked per source file by a test. The lower layers know nothing of governance, power or objectives; those are supplied from above.
ssf.designs ──▶ everything below named cases; every parameter carries a reason ssf.search ──▶ reconstruct, core interventions, objectives, non-dominated sets ssf.power ──▶ reconstruct, measure divergence-based power, influence, asymmetry ssf.reconstruct ──▶ observe, measure fit, penalty, ensemble ssf.history ──▶ measure histories, transition weights, marginals ssf.weights · ssf.observe · ssf.measure ──▶ complex, labels ssf.complex · ssf.labels ──▶ nothing above
One module is not obvious and is load-bearing. ssf.provenance tags every local weight as stipulated or estimated, and a parameter without a stated reason will not construct. The account's second-most-severe limit is that the local weights are not derived — a society supplies no action to extremise and the labels carry no group — and every number on this page rests on stipulated ones. So printing a result prints the mix that produced it:
rests on stipulated weights throughout — a demonstration of the procedure, not a social fact
Invariants the code enforces
| Invariant | How it is enforced |
|---|---|
| Type is not dimension | a test walks the syntax tree of every module for dimension-conditioned type logic |
| A relation may hold between relations | a conformance case builds it and couples to it |
| One admissibility structure, not two | is_admissible is weight > 0; a graded weight and its Boolean indicator must agree on every verdict |
| Weights non-negative, no complex amplitude | constructors reject negatives; monotonicity over 200 randomised path deletions |
| Reconstruction returns an ensemble | the signature, plus a test that argmax / best / most_likely do not exist |
| Power is scale-invariant | 20 random common rescalings; every value unchanged to 10−9 |
| Search returns a set | no best or select; a scan of every source file for the word for a winner |
| Objectives declare their neutrality | an objective without one raises; the design's two supplied objectives are labelled |
| Provenance travels with the number | a parameter without a reason raises; ensembles report their mix |
| Vocabularies are arguments, never constants | a test asserts the core instantiates no type system and names no social type |
| Layers run downward only | a per-file import check |
The last is the sharpest, and it is the framework turned on itself. Variation of the type system and the observables is the third level of power — what can be recorded, and therefore what can be claimed — and the account names the analyst's supply of that system as an act at exactly that level. A library shipping a default would be performing it on behalf of everyone who imported it.
Where the work stands
Eight phases, each with a deliverable and the acceptance test that closes it. Phases 0–5 and 7 have landed; Phase 6 is next, and it is the hard one.
Structure and labels
Two-complexes with incidence, a dimension guard, and labellings over analyst-supplied vocabularies. The paper's worked instance builds — three faces, two edges, one vertex where the couplings meet — and a conformance case builds a relation between two relations.
Weights and admissibility
Face, coupling and vertex weights; the configuration weight as one local pass; admissibility as strict positivity. Provenance tagging lands here, since a weight without a provenance should never be constructible.
Histories, transition weights, marginals
Histories with boundary, exhaustive transition sums, marginals, normalisation and divergence. Monotonicity under path deletion holds over randomised removals, and the cancellation diagnostic returns the right verdict on constructed data of both kinds.
Observation and reconstruction
Observation records with confidences, compatibility by injection, fit, description length, the objective, the ensemble — and the scholarship design. The ensemble reproduces the paper's table to three decimals and the marginal to 0.268.
Power
Divergence-based power, directed influence, normalised asymmetry, the four kinds of act. The three suppressions and the coupling act reproduce, and scale-invariance holds under random common rescaling.
Interventions and search
The four edit kinds, availability, objective vectors with declared neutrality, dominance and non-dominated sets. The minimal case's set reproduces, the all-edits candidate is confirmed dominated, and three weightings select two different members.
Scale: grammar-guided variation, sampled histories
Variation operators must be admissibility-preserving, since unconstrained mutation drives a candidate's weight to zero and fills a population with candidates carrying no information for selection. And evaluation is nested — every candidate's evaluation contains a sum over histories — so the cost is the product of two loops. Three reductions exist, each with a price that must be reported alongside the result. The trap is a scalability claim: the paper makes none, and neither should the code.
Figures
Five, generated from the implementation under a recorded seed. Deleting the output directory and re-running reproduces them, so a stale figure is a bug rather than a merge conflict, and every number drawn is computed rather than typed in.
What is not planned, and why
No criterion of justice. The search returns a set; choosing within it requires a criterion the framework does not supply, and supplying one in code would hide that.
No derivation of the local weights. A society supplies no action to extremise and the labels carry no group. Weights are estimated from observed frequencies or stipulated from institutional knowledge, and which one is always recorded.
No default type system, coupling repertoire or label space. Supplying them is an act of power, and the framework does not exempt itself from its own analysis.
No scalability claim. Evaluation is nested, and the three available reductions each carry a cost reported with the result.
No application to observed social data. The scholarship case is invented, describes no existing arrangement, and names no jurisdiction. Every number on this page rests on stipulated weights and demonstrates the procedure rather than any social fact.
Standing, licence & invitation
The specification is a preliminary discussion paper, offered to share an evolving idea and to invite dialogue, criticism, revision and independent development. Its author claims no exclusive epistemic ownership over the viewpoints, concepts or lines of reasoning in it, and no priority as their first originator. This repository exists partly so that those ideas can be run — and partly so that disagreement with them can be made precise, as the two findings above were.
The project is classified under Domain IV (Decision) of Schedule A, with Domain I (Theoretical and Ontological) and Domain VII (Normative) as secondaries. The software is released under the MIT Licence; the manuscript keeps the CC BY-NC 4.0 licence stated in its own Notices.
A formal project-approval instrument (SCS/PA/…) has not yet been issued for this project; the specification paper is a working draft, and this page will be updated when one is adopted.