pgx
PGX — Lightweight Postgres for AI agents. Written in Rust. Thousands of isolated databases in one runtime. 🐘
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Source-backed atlas of political, military, security and economic power in Tunisia, 1956–2026
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗deeptunisia.org — an open-source public-interest research project documenting Tunisia's political, institutional, economic and historical power structures through verifiable evidence, 1956–2026.
It is not a website exposing a deep state. That framing presupposes its own conclusion, and a project that begins from a conclusion cannot be trusted to test it. The narrower question is answerable: which institutions, individuals and economic groups retain influence when the formal regime changes, and which relationships are genuinely continuous rather than reconstructed after each rupture. On the evidence page you can watch the data support that question and refuse it — two of six hypotheses currently come out badly, including the strong version of the deep state thesis.
The website is a window. The knowledge graph is the project.
# Fresh clone, in this order:
npm ci --ignore-scripts
npm run build # graph + landing page (the landing page is hash-tied to the dataset)
npx svelte-kit sync # generate the $data alias the test suites import
npm run test # all suites
npm run check # svelte-check — must be 0 errors, 0 warnings
# Day to day:
npm run dev # builds the graph, then starts the dev server on :5173
npm start # atlas on :5173 AND the Agora API on :5200, one command
npm run build # validates, exports, and produces a static site in build/
npm run smoke # real browser, both themes, desktop AND phone — needs a dev server (mode defaults to beta; override with VITE_COMMUNITY_MODE)
npm run feed # fetch news headlines into feed/ (also runs every 4h in CI)
npm run audit:probes # reproduce the external code review's compiler probes
npx svelte-kit sync is required before npm run test on a fresh clone: the suites import the $data alias, which SvelteKit generates. npm run build is required too, because landing/index.html is hash-tied to the generated dataset and the drift gate fails otherwise. The ci workflow runs the same sequence on a clean runner.
The atlas itself needs no server, no database, no API and no accounts — the
static site ships as files. The discussion layer (Agora) is separate: a
community API with a D1 database and pseudonymous identity, closed in
production by a server-enforced mode. COMMUNITY_MODE=off in wrangler.toml
makes every Agora /api/* route answer the same 404 before it touches the database
(research routes under /api/studies/ have their own closed-by-default gate);
the interface only reports that state and cannot open it. npm start runs both
halves of the dev loop as beta so the Agora tab is reachable during
development; a reader on deeptunisia.org never touches it. The mode contract is
docs/agora-deployment.md.
The complete graph is 5070 KB as the internal
bundle, and the public exports (dataset, CSVs, geographic layers, changelog)
ship at 8950 KB — both are computed by the
build, and npm run test fails if the README ever disagrees with them.
Two builds from the same commit and the same data/ produce the same graph.
The build validates and exports into staging directories (src/generated.tmp/
and static.tmp/), then promotes them file by file only after every check
passes. A failed build publishes nothing: not dataset.json, not the CSV
exports, not editorial-queue.json.
meta.datasetHash is a sha256 over the canonical projection of the graph:
object keys sorted, meta.generated replaced by a fixed placeholder, payload
sizes excluded, records in their emitted order. npm run test recomputes it
and fails if the emitted file disagrees with its own hash.
To compare two builds byte for byte:
DT_CANONICAL=1 npx tsx scripts/build-data.ts
Canonical bytes are identical for the same commit and the same data; release
metadata (meta.generated, shippedKB, datasetKB) is not. stats.json
publishes datasetHash, lockHash (the dependency lockfile), node (the
runtime) and commitSha, so a release can be identified without trusting the
clock. See scripts/canonical.ts.
The in-product orientation page — each view's one-sentence answer, when to use it, and the four-basis legend — lives at /guide and is the maintained copy; this table mirrors it and must be kept in step.
| View | What it answers |
|---|---|
| Chronicle | Who held which post, when, drawn to scale. Bar length is tenure, so continuity is visible without reading. |
| Now | Who holds which office today — split by how recently each was verified, and measured against that office's historical median tenure. |
| Network | Who connects to whom. Fixed lane per layer, so cross-layer bridges are literally the edges that cross lanes. |
| Atlas | Everything at once: structure per era as small multiples, a survival matrix of people against eras, an institution-crossing matrix, and median tenure per office. |
| Rankings | Six separate structural indices with reader-adjustable weights. Deliberately no single power score. |
| Map / World | Tunisian governorates and strategic assets with sourced coordinates; Tunisia's place among states and international organisations. |
| Investigate | Structured queries over the graph. Computed by traversal, never generated by a language model. |
| Evidence | Hypotheses with falsifiers, open questions, unresolved source contradictions, every citation. |
| Research | Open studies of Tunisian public opinion, with pre-registered methods and open data. |
| Agora | Discussion, proposed changes and reports — closed in production by a server-enforced mode. Everything here is unreviewed public text, deliberately rendered in a register no sourced claim ever wears. |
Plus /methodology, /corrections (every change to the dataset, generated from version control), /about (governance, funding transparency, honest status) and /data (the full graph, downloadable under CC BY 4.0 — the code is MIT; see LICENSE and data/LICENSE). Media holds the in-house investigations and the third-party Feed; the feed carries its own notice that it is not DeepTunisia data.
An inference is never allowed to become a fact. Every claim is filed under one of four bases, and they never render identically:
| Basis | Meaning | Rendering |
|---|---|---|
documented | An official record, decree or gazette entry states it | Solid |
reported | Credible publications report it, with attribution | Dashed |
inferred | Nobody states it; reasoned from documented structure | Dotted |
unsubstantiated | Circulates without reliable evidence | Dot-dash, off by default |
The evidence dial sets the floor. Raising it to documented-only visibly dissolves much of the network, which is the most informative interaction on the site.
Unsubstantiated claims are recorded, not deleted. Deleting a widely-held claim does not make it go away; it means the map cannot show anyone why the popular account is wrong. Several on record here are contradicted by this project's own data — the claim that the army secretly governs Tunisia, for instance, sits next to the record of the tri-service command going unfilled for two decades.
Two obligations are enforced by the build, as hard failures:
inferred claim must state its reasoning and what would falsify it.There is no way to slip an unattributed insinuation into this dataset.
data/
sources.yaml every citation, tiered 1-5, with archive lookups
eras.yaml seven periods, each with an explicit thesis
institutions.yaml the command tree, layered, incl. foreign actors
roles.yaml canonical offices + the published authority weight table
people.yaml names in three scripts, aliases, trajectories
positions.yaml (person x role x span) — the join that makes time-travel work
relationships.yaml typed, dated, based edges
events.yaml with competing framings and source disputes side by side
questions.yaml what is still unknown
hypotheses.yaml falsifiable claims with honest verdicts
Six decisions carry most of the weight:
Positions are the join table. A Position is (role, holder, start, end). You cannot ask "who held power in 1994" from a list of people, only from a set of intervals.
Dates are ranges, not points. Four fields — earliest/latest start, earliest/latest end — plus a status (ended, ongoing, last-verified, unknown). The Chronicle draws the documented core solid and the uncertain envelope hatched. Grammar: 2018-06-01, 2018-06, 2018, ~2017, <=2018-06, ongoing, verified:2025-12, ?.
Basis describes the claim, not its dates. A position bundles two separable claims — "X held this post" and "between these dates" — which routinely have different standing. A security chief whose office is well reported but whose start date nobody published is a reported officeholding with an inferred span. datesInferred is a separate flag so imprecise dating never looks like speculation.
Successions are derived, not asserted. Computed from the position records, so a hole shows up as a hole: currently 43 gaps and 2 overlapping tenures, all published.
Change is a record too. The dataset is plain text under version control, so every factual change is a dated, attributable diff. /corrections publishes that history — generated, not curated, so nobody decides which changes are flattering enough to appear.
Disagreement is a record, not a problem to resolve. When sources conflict, both are stored with who holds each and whether it was adopted. Currently 69 recorded contradictions, including one where five different sentence lengths circulated across outlets for overlapping proceedings and the dataset declines to guess how many cases there were.
/feed shows headlines other people published. It is not DeepTunisia data, and the separation is structural rather than a disclaimer:
feed/, never data/. The graph build does not read it.npm run test asserts all of the above, including that the fetcher touches exactly one path and never disables TLS verification.Names in headlines are linked to graph entities by deterministic string matching, never a language model, so every link is explainable by the surface form that produced it. A highlight means the headline contains a name the graph knows — not that the article is about that person, and not that any of it is true.
Surname-only matches are refused. The matcher can only measure distinctiveness against the few hundred people recorded here, and Tunisia has around twelve million: on real headlines that rule linked a 2012 interim finance minister to a story about solar batteries. scripts/test-match.ts pins the decision with those fixtures.
/media prints two sets of numbers for each investigation, and they count different things:
src/content/media/<slug>/research.yaml, written during the research sweep. Sources consulted, claims extracted before any editorial cut, the sweep's own disputed and unresolved tallies.src/generated/media/index.json, counted at build time from the ledgers that ship: claims in evidence.yaml, sources cited in sources.yaml, disputed and unresolved among the shipped claims.They are independent populations. Neither is derived from the other, they are never summed, and they are not expected to match: consultation counts what was opened, the index counts what survived curation. The investigation page keeps them apart for that reason, the evidence profile counting the shipped ledger and the research block counting the sweep. scripts/build-media.ts carries the same statement beside the code that emits the index.
Editorial state is separate from both counts. status and reviewer come from each investigation's editorial.yaml, checked against meta.yaml at build time, and rendered wherever the piece appears. A draft investigation is a live route, so the index card, the investigation page and the article header each say that it is a draft, in English, French and Arabic, and a piece with no reviewer reads "No reviewer recorded." rather than implying a review that did not happen. npm run test:media pins all of it, including the refusal to ship a status the vocabulary does not define.
data/sources.yaml first, with a tier. Tier 1 is a decree or gazette entry; tier 5 is a lead that needs corroborating and is never sufficient alone.C + attributed_to. Reasoned estimate → basis: inferred + reasoning + falsifiable_by.npm run data, then npm run test. Fix what they reject.Prefer gazette appointment decrees above everything else: they give exact dates, which is what the whole timeline depends on.
Bourguiba, Ben Ali, Saied, Ennahda, the opposition, the military, the police, the business families, the unions, the EU, France, Italy, Algeria, the US, Russia, the World Bank and international NGOs are all in the graph under identical rules. An atlas of Tunisian power containing only Tunisians reads as an indictment of Tunisians.
This is not neutrality for its own sake — it is the project's only real protection. Credibility that depends on people agreeing with the conclusions collapses the moment they don't. Credibility that depends on the evidence being accessible and reproducible does not.
/about because that is the only way the commitment means anything.<= bounds use an 8-year window. Stated modelling assumption, not a fact./evidence./about.The ingestion pipeline (discovery → extraction → entity resolution → evidence attachment → contradiction detection → human verification → graph) is designed and the schema supports it: review provenance, disputes, alias-based entity resolution. It is not built, because the automatable parts are the easy parts and building volume before verification capacity exists would produce exactly the failure mode this project is meant to correct.
Same for the assisted research layer. When it comes, it must traverse this graph and cite records — never generate the answer.
A high brokerage score means the dataset records someone connecting otherwise separate networks. It is not evidence of wrongdoing, coordination or hidden control.
A prison sentence is a documented fact. The allegations behind it and the criticism of the proceedings are contested; both framings are stored with attribution rather than adjudicated.
Wealth is not corruption. The dataset distinguishes established business families from politically created ones, because collapsing that distinction is the most common error in popular accounts — the Mabrouk fortune predates Ben Ali; a marriage brought one branch inside the presidential family; the same person was later imprisoned by the successor state. All three facts have to survive contact with each other.
Two products, two terms, one repository.
src/, scripts/, community/, landing/, build config —
is MIT. See LICENSE.data/*.yaml, the generated bundle, and the
public exports under static/ — is CC BY 4.0 (attribution only; reuse
freely, including commercially, keep the credit). See data/LICENSE.The underlying cited sources (gazette entries, articles, archives) remain under their own terms; the data license covers the project's selection, arrangement, translations and analytical framing — not the third-party material the citations point to. Facts are not copyrightable, and every claim in the dataset names the sources it rests on.
SvelteKit (static adapter) · Svelte 5 runes · TypeScript · Zod-validated YAML → JSON at build time · D3 scales with hand-rolled SVG · graphology for centrality · MiniSearch.