docs: public-release README; ci: GitHub Actions workflow
README rewritten for a public audience: what the tool is and is not (the not-validated disclaimer up front), the model with literature references (Holme & Kim 2002; Kempe, Kleinberg & Tardos 2003), honest status checklist, quick start, layout, the generated-types rule, and the prevention-only framing of the subject. CI mirrors the local checks (go test, gofmt, golangci-lint, vue type-check/lint/test/build) and adds a drift guard: go generate must leave web/src/types/ unchanged, so the Go structs stay the single source of truth in fact, not just in principle.
This commit is contained in:
parent
a57e729c10
commit
61af68a8f7
2 changed files with 153 additions and 21 deletions
54
.github/workflows/ci.yml
vendored
Normal file
54
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Runs the same checks as the README's "Checks" section, plus a guard that
|
||||
# the generated TypeScript types are in sync with the Go structs.
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
go:
|
||||
name: Go (test, lint, generated types)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
- name: Test
|
||||
run: go test ./...
|
||||
- name: gofmt
|
||||
run: test -z "$(gofmt -l .)"
|
||||
- name: Generated types are in sync
|
||||
run: |
|
||||
go generate ./...
|
||||
git diff --exit-code web/src/types/
|
||||
- name: Lint
|
||||
uses: golangci/golangci-lint-action@v8
|
||||
with:
|
||||
version: latest
|
||||
|
||||
web:
|
||||
name: Web (type-check, lint, test, build)
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: web
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: npm
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- name: Install
|
||||
run: npm ci
|
||||
- name: Type-check
|
||||
run: npm run type-check
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
- name: Unit tests
|
||||
run: npm run test:unit -- --run
|
||||
- name: Build
|
||||
run: npm run build
|
||||
120
README.md
120
README.md
|
|
@ -1,45 +1,123 @@
|
|||
# spreadlab
|
||||
|
||||
Self-hosted dashboard that runs an agent-based deepfake-spread model live:
|
||||
change the levers, watch the spread, and (later) search for the best
|
||||
intervention under a budget. Output is illustrative, not validated.
|
||||
[](https://github.com/JustinZeus/spreadlab/actions/workflows/ci.yml)
|
||||
|
||||
Status: milestone 2, thin API + parity page done.
|
||||
An agent-based "what if" dashboard for a hard question: when harmful content
|
||||
(the modelled case: a non-consensual deepfake) starts spreading through a
|
||||
school year group, where does a limited education budget actually make a
|
||||
difference?
|
||||
|
||||
## Layout
|
||||
> **Illustrative, not validated.** spreadlab is a planning and discussion
|
||||
> aid. The model is a deliberately simple social-contagion simulation; its
|
||||
> numbers are not predictions about real schools, real platforms, or real
|
||||
> incidents, and must not be used as such.
|
||||
|
||||
- `internal/engine/` - the pure simulation engine (no web dependencies)
|
||||
- `internal/api/` - thin JSON API over the engine
|
||||
- `cmd/spreadlab/` - the server binary (`-table` prints a CLI comparison)
|
||||
- `web/` - Vue 3 + TypeScript frontend (Vite)
|
||||
- `web/src/types/` - TypeScript types GENERATED from the Go structs; never
|
||||
edit by hand, regenerate with `go generate ./...`
|
||||
## The idea
|
||||
|
||||
## Development
|
||||
Schools can rarely reach everyone with a prevention program. spreadlab runs
|
||||
the *same* outbreak in the *same* simulated social network under different
|
||||
education strategies, so the only thing that changes is who gets educated.
|
||||
With the default world (120 students, educate 30% of them):
|
||||
|
||||
One command (installs frontend deps on first run, Ctrl-C stops everything):
|
||||
| Strategy | Reached by the fake |
|
||||
| -------------------------- | ------------------- |
|
||||
| No program | 82% |
|
||||
| Educate 30% at random | 58% |
|
||||
| Educate the 30% best-connected | 6% |
|
||||
|
||||
Same budget, different targeting, an order-of-magnitude difference. Making
|
||||
that lever visible (and later: searching for the best intervention under a
|
||||
budget) is the point of the tool.
|
||||
|
||||
## How the model works
|
||||
|
||||
- **Network**: Holme-Kim preferential attachment with triangle closure
|
||||
(Holme & Kim, 2002), producing the hubs and clustered friend groups of
|
||||
real social networks; a port of networkx's `powerlaw_cluster_graph`.
|
||||
- **Spread**: an independent cascade (Kempe, Kleinberg & Tardos, 2003);
|
||||
each directed edge gets one random forwarding draw, shared across all
|
||||
scenarios, so strategies are compared in the same world.
|
||||
- **Education lever**: an educated student still receives the fake but
|
||||
never forwards it. Strategies: no program, uniform random, most-connected.
|
||||
- **Determinism**: every source of randomness flows from seeds in the
|
||||
config; identical configs produce identical results, pinned by tests.
|
||||
|
||||
## Status
|
||||
|
||||
Early development; interface and API are not stable yet.
|
||||
|
||||
- [x] Simulation engine in Go (tested, deterministic, benchmarked)
|
||||
- [x] JSON API + TypeScript types generated from the Go structs
|
||||
- [x] Web frontend reproducing the three-scenario comparison from live data
|
||||
- [ ] Interactive dashboard (controls, network view, spread animation)
|
||||
- [ ] Single-binary deploy (embedded frontend), Docker image, hosted demo
|
||||
- [ ] Intervention optimisation under a budget
|
||||
|
||||
## Quick start (development)
|
||||
|
||||
Prerequisites: Go 1.26+, Node 20+.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/JustinZeus/spreadlab
|
||||
cd spreadlab
|
||||
./dev.sh
|
||||
```
|
||||
|
||||
Or manually, in two terminals:
|
||||
`dev.sh` starts the Go API (localhost:8080) and the Vite dev server
|
||||
(localhost:5173, proxying `/api`), and installs frontend dependencies on
|
||||
first run. One Ctrl-C stops everything. Or run the two halves manually:
|
||||
|
||||
```sh
|
||||
go run ./cmd/spreadlab # API on localhost:8080
|
||||
cd web && npm run dev # Vite dev server, proxies /api to :8080
|
||||
cd web && npm run dev # frontend on localhost:5173
|
||||
```
|
||||
|
||||
Checks:
|
||||
`go run ./cmd/spreadlab -table` prints the three-scenario comparison to the
|
||||
terminal as a quick engine sanity check.
|
||||
|
||||
## Project layout
|
||||
|
||||
| Path | What it is |
|
||||
| ------------------ | ------------------------------------------------------- |
|
||||
| `internal/engine/` | Pure simulation engine; no web dependencies |
|
||||
| `internal/api/` | Thin JSON API over the engine |
|
||||
| `cmd/spreadlab/` | Server binary |
|
||||
| `web/` | Vue 3 + TypeScript frontend (Vite) |
|
||||
| `web/src/types/` | TypeScript types generated from the Go structs |
|
||||
|
||||
The Go structs in `internal/engine/scenario.go` are the single source of
|
||||
truth for parameters and results. `web/src/types/` is generated from them
|
||||
(via [tygo](https://github.com/gzuidhof/tygo)); never edit those files by
|
||||
hand. After changing `Config`, `Result`, or the API response types:
|
||||
|
||||
```sh
|
||||
go test ./... # engine + API tests
|
||||
golangci-lint run ./... # Go linter
|
||||
go generate ./...
|
||||
```
|
||||
|
||||
## Checks
|
||||
|
||||
```sh
|
||||
go test ./... # engine + API tests
|
||||
golangci-lint run ./... # Go linter
|
||||
go test -bench=. -benchmem ./internal/engine/ # benchmark baseline
|
||||
cd web && npm run test:unit && npm run lint && npm run type-check
|
||||
```
|
||||
|
||||
After changing `Config`, `Result`, or the API response types, run
|
||||
`go generate ./...` and commit the regenerated files in `web/src/types/`.
|
||||
CI runs the same checks, plus a guard that the generated TypeScript types
|
||||
are in sync with the Go structs.
|
||||
|
||||
MIT licensed.
|
||||
## Background
|
||||
|
||||
spreadlab started as the proof-of-concept tool of a university grant
|
||||
proposal on AI in an open society; the model semantics were ported from the
|
||||
Python prototype used in that project's pitch. The subject is handled from
|
||||
the prevention side only: the tool models how harmful content spreads and
|
||||
what education changes, nothing about creating such content.
|
||||
|
||||
References: P. Holme & B. J. Kim, *Growing scale-free networks with tunable
|
||||
clustering* (Phys. Rev. E 65, 2002). D. Kempe, J. Kleinberg & E. Tardos,
|
||||
*Maximizing the spread of influence through a social network* (KDD 2003).
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue