evidence.claim
Jedno tvrzení se stavem jeho důkazu, za ním stojící provedení — výsledek, doba trvání, commit, stav stromu, digest, čas a původ — příkaz, který ho reprodukuje, a další tvrzení, která dokládá tentýž test. Tvrzení, které matice nedeklaruje, je not-found, nikoli prázdná odpověď, protože překlep, který by se četl jako „toto tvrzení nemá důkazy“, je jediná odpověď, kterou tato schopnost nesmí dát.
Jedno tvrzení se stavem jeho důkazu, za ním stojící provedení — výsledek, doba trvání, commit, stav stromu, digest, čas a původ — příkaz, který ho reprodukuje, a další tvrzení, která dokládá tentýž test. Tvrzení, které matice nedeklaruje, je not-found, nikoli prázdná odpověď, protože překlep, který by se četl jako „toto tvrzení nemá důkazy“, je jediná odpověď, kterou tato schopnost nesmí dát.
- query
- behaviorally_verified
- module evidence
- #evidence
- #claims
- #verification
- #provenance
Zpřístupnění
Kde je tato jedna definice dosažitelná. Absence je explicitní: povrch, který není uveden, ji nenese.
| povrch | jako |
|---|---|
| MCP | nástroj majordomus_evidence_claim |
| HTTP | GET /api/v1/evidence/claim operationId evidence.claim |
| příkazová řádka | majordomus evidence claim |
Schémata
Kanonický vstup a výstup z typů Rustu; schéma nástroje MCP a parametry a odpovědi OpenAPI se odvozují z nich.
input · EvidenceClaimInput
Id je povinné a neexistuje žádný zápis tohoto vstupu, který by znamenal „každé tvrzení“ — ta otázka patří evidence.report. Id, které matice nedeklaruje, je z handleru not-found, ne prázdný důkaz.
use majordomus_cli::capability::builtin::evidence::EvidenceClaimInput;
let input: EvidenceClaimInput =
serde_json::from_str(r#"{"claim": "evidence-both-directions"}"#).unwrap();
assert_eq!(input.claim, "evidence-both-directions");
// no id is a usage error, never a request for all of them
assert!(serde_json::from_str::<EvidenceClaimInput>("{}").is_err());| vlastnost | typ | povinné | popis |
|---|---|---|---|
| claim | string | ano | Id tvrzení tak, jak ho zapisuje docs/CLAIMS.yaml. |
JSON Schema
{
"additionalProperties": false,
"description": "One claim of the matrix, named by the id it is declared under.\n\nThe id is required, and there is no spelling of this input that means \"every claim\" —\nthat question belongs to `evidence.report`. An id the matrix does not declare is a\nnot-found from the handler rather than an empty proof.\n\n```\nuse majordomus_cli::capability::builtin::evidence::EvidenceClaimInput;\n\nlet input: EvidenceClaimInput =\n serde_json::from_str(r#\"{\"claim\": \"evidence-both-directions\"}\"#).unwrap();\nassert_eq!(input.claim, \"evidence-both-directions\");\n\n// no id is a usage error, never a request for all of them\nassert!(serde_json::from_str::<EvidenceClaimInput>(\"{}\").is_err());\n```",
"properties": {
"claim": {
"description": "The claim id, as `docs/CLAIMS.yaml` spells it.",
"type": "string"
}
},
"required": [
"claim"
],
"title": "EvidenceClaimInput",
"type": "object"
}výstup · ClaimEvidence
Důkaz je do odpovědi zploštěn, takže klient čte jedno tvrzení, ne obal důkazu kolem něj; provedení a ostatní tvrzení, která tentýž test dokazuje, leží vedle něj.
use majordomus_cli::capability::builtin::evidence::ClaimEvidence;
use majordomus_cli::evidence::ClaimProof;
let proof: ClaimProof = serde_json::from_value(serde_json::json!({
"id": "evidence-both-directions",
"claim": "a claim and its test answer for each other",
"status": "guaranteed",
"source": null,
"implementation": null,
"test_path": "test/cases/84_distribution_model.sh",
"test": "suite:84_distribution_model",
"state": "not_run",
"meaning": "no run of this test has been recorded",
"execution": null,
"changed": [],
"reproduce": "bash test/run.sh 84_distribution_model"
}))
.unwrap();
let answer = ClaimEvidence {
proof,
executions: Vec::new(),
also_proves: vec!["evidence-record-is-not-networked".to_string()],
};
let json = serde_json::to_value(&answer).unwrap();
assert_eq!(json["id"], "evidence-both-directions");
assert!(json.get("proof").is_none(), "the claim is flattened in, not nested");
assert_eq!(json["also_proves"], serde_json::json!(["evidence-record-is-not-networked"]));
// a list even where the ledger keeps one: retention is a decision that may change,
// and a client that read a bare object would break when it did
assert_eq!(json["executions"], serde_json::json!([]));| vlastnost | typ | povinné | popis |
|---|---|---|---|
| also_proves | array | ano | Další tvrzení, která dokládá stejný test. Test sdílený dvanácti tvrzeními je test, jehož selhání je dvanáct nálezů, a čtenář jednoho z nich by měl vidět dalších jedenáct bez hledání. |
| změněno | array | ano | Soubory, které toto tvrzení jmenuje a které se liší mezi zaznamenaným commitem a pracovním stromem. Prázdné, dokud stav není ProofState::Stale.
Vždy vydáváno, i prázdné: schéma, které tato schopnost publikuje, říká, že klíč tam je, a klient, který musí rozlišit „žádné soubory se nezměnily“ od „server to neřekl“, čte dvě různé odpovědi jako jednu. |
| claim | string | ano | Věta tvrzení. |
| detail | string | null | ne | Proč je stav takový, jaký je, jednou větou, když to samotný stav neříká: test, který odmítl běžet, běh na commitu, který předložená revize neobsahuje, strom, který nebyl svým commitem, selhávající běh, který checkout drží necommitnutý. |
| provádění | jedno ze 2 | ne | Provedení, ze kterého se stav odvodil, pokud nějaké je. |
| executions | array | ano | Každé provedení, které kniha drží pro test tohoto tvrzení — dnes jedno, poslední, a seznam proto, že uchovávání v knize je rozhodnutí, které se může změnit, a klient čtoucí holý objekt by se při změně rozbil. |
| id | string | ano | Id tvrzení, jak ho zapisuje docs/CLAIMS.yaml. |
| implementace | string | null | ne | Soubor, který ji implementuje. |
| význam | string | ano | Tento stav v jedné větě. |
| reprodukovat | string | null | ne | Příkaz, který důkaz vytvoří znovu, když test vlastní runner. |
| zdroj | string | null | ne | Dokument, který definuje chování. |
| state | reference | ano | Co o důkazu může repozitář říct. |
| status | string | ano | Stav, který tvrzení deklaruje: guaranteed, advisory, planned, rejected. |
| test | string | null | ne | Stabilní identita testu, pokud ji vlastní runner. |
| test_path | string | null | ne | Cesta, kterou tvrzení jmenuje jako svůj test, doslova. |
JSON Schema
{
"$defs": {
"EvidenceExecution": {
"description": "One recorded run of one test: the whole of what this repository durably remembers about\nit.\n\nEvery field is provenance. A result with no commit is an anonymous green, which is the\nthing a badge must never be derived from.\n\n```\nuse majordomus_cli::evidence::{digest_of, Execution, Origin, Outcome, Runner, TestId};\n\nlet id = TestId::of(\"apps/majordomus-cli/tests/why.rs\").unwrap();\nlet run = Execution {\n test: id.as_string(),\n runner: Runner::Crate,\n source: id.source(),\n outcome: Outcome::Pass,\n seconds: 12,\n commit: \"0\".repeat(40),\n working_tree: \"clean\".into(),\n digest: digest_of(b\"fn main() {}\"),\n at: \"2026-09-11T00:00:00Z\".into(),\n origin: Origin::Ci,\n command: id.reproduce(),\n run: None,\n};\n\n// it is a value in a tracked JSON file, so it has to survive the file unchanged\nlet back: Execution = serde_json::from_str(&serde_json::to_string(&run).unwrap()).unwrap();\nassert_eq!(back, run);\nassert_eq!(back.test, \"crate:why\");\nassert_eq!(back.command, \"cargo test --test why\");\n```\n# Example\n\nOne recorded run, with the provenance the runner did not carry: which commit, which\ntree state, the digest of the test's own source, when, and how to run it again.\n\n```\nuse majordomus_cli::evidence::{Execution, Origin, Outcome, Runner};\nlet e = Execution {\n test: \"suite:07_scope\".into(),\n runner: Runner::Suite,\n source: \"test/cases/07_scope.sh\".into(),\n outcome: Outcome::Pass,\n seconds: 3,\n commit: \"a04b65c9\".into(),\n working_tree: \"clean\".into(),\n digest: \"sha256:00\".into(),\n at: \"2026-09-11T00:00:00Z\".into(),\n origin: Origin::Local,\n command: \"bash test/run.sh 07_scope\".into(),\n run: None,\n};\nassert!(e.outcome.proves());\n```",
"properties": {
"at": {
"description": "When it was recorded, RFC 3339, UTC.",
"type": "string"
},
"command": {
"description": "The exact command that runs this one test again.",
"type": "string"
},
"commit": {
"description": "The full commit id the run was made against.",
"type": "string"
},
"digest": {
"description": "`sha256:<hex>` of the test's own source as it was when the run was recorded. An\nexecution whose test no longer hashes to this did not run the test that is there now.",
"type": "string"
},
"origin": {
"$ref": "#/$defs/EvidenceOrigin",
"description": "Where the run happened."
},
"outcome": {
"$ref": "#/$defs/EvidenceOutcome",
"description": "What it said."
},
"run": {
"anyOf": [
{
"$ref": "#/$defs/EvidenceRun"
},
{
"type": "null"
}
],
"description": "The continuous-integration run the execution was recorded in, when it was recorded in\none that could name itself. Absent for a local run, and absent from every row recorded\nbefore runs were named, which is why the ledger's version did not change."
},
"runner": {
"$ref": "#/$defs/EvidenceRunner",
"description": "Which runner produced it."
},
"seconds": {
"description": "How long it took, in whole seconds.",
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"source": {
"description": "The test's own source, repository-relative.",
"type": "string"
},
"test": {
"description": "The test, in `TestId::as_string` form.",
"type": "string"
},
"working_tree": {
"description": "`clean`, `dirty` or `unknown`: whether the tree the run measured was the commit.",
"type": "string"
}
},
"required": [
"test",
"runner",
"source",
"outcome",
"seconds",
"commit",
"working_tree",
"digest",
"at",
"origin",
"command"
],
"type": "object"
},
"EvidenceOrigin": {
"description": "Where a run happened. The canonical model is provider-neutral: a CI adapter records\n`Ci`, and nothing here knows or cares which CI it was.\n\n```\nuse majordomus_cli::evidence::Origin;\n\nassert_eq!(Origin::parse(\"CI\"), Some(Origin::Ci));\nassert_eq!(Origin::parse(\"local\"), Some(Origin::Local));\n// naming the provider is the adapter's business; the ledger records the kind of run,\n// so a repository that changes CI does not change what its old evidence says\nassert!(Origin::parse(\"github-actions\").is_none());\n```\n# Example\n\n```\nuse majordomus_cli::evidence::Origin;\nassert_eq!(Origin::parse(\"ci\"), Some(Origin::Ci));\nassert_eq!(Origin::parse(\"nowhere\"), None);\n```",
"oneOf": [
{
"const": "local",
"description": "Someone ran it on their own machine.",
"type": "string"
},
{
"const": "ci",
"description": "A continuous-integration run.",
"type": "string"
},
{
"const": "release",
"description": "A release run.",
"type": "string"
}
]
},
"EvidenceOutcome": {
"description": "What a run said about one test.\n\n`NotRun` is deliberately absent: it is the absence of an execution, not an outcome one\nhad. Encoding it here would let a recorder write \"this did not run\" and have it counted\namong the things that did.\n\n```\nuse majordomus_cli::evidence::Outcome;\n\nassert!(Outcome::parse(\"ok\").proves());\nassert!(!Outcome::parse(\"timeout\").proves());\n// exactly one of the five is evidence of anything; the other four are reasons there\n// is none, kept apart because \"it declined\" and \"the harness broke\" are different bugs\nassert_eq!(Outcome::parse(\"skipped\"), Outcome::Skip);\nassert_eq!(Outcome::parse(\"nonsense\"), Outcome::Error);\n```\n# Example\n\n```\nuse majordomus_cli::evidence::Outcome;\nassert!(Outcome::parse(\"ok\").proves());\nassert_eq!(Outcome::parse(\"wat\"), Outcome::Error);\n```",
"oneOf": [
{
"const": "pass",
"description": "It passed.",
"type": "string"
},
{
"const": "fail",
"description": "It failed.",
"type": "string"
},
{
"const": "skip",
"description": "It declined to run and said so (an unmet precondition the case reports itself).",
"type": "string"
},
{
"const": "timeout",
"description": "The bound fired before it finished.",
"type": "string"
},
{
"const": "error",
"description": "The harness could not run it at all.",
"type": "string"
}
]
},
"EvidenceRun": {
"description": "The continuous-integration run an execution was recorded in: enough to navigate back to\nthe run that produced it.\n\n`Origin` says what kind of run it was and deliberately names no provider. This names the\none run, in the words the provider addressed it with when it happened — its identifier,\nits attempt, the workflow and job, and the address a reader follows — because a link built\nlater from a template would point wherever the template's idea of the provider had drifted\nto. Only an adapter constructs it; nothing in the model reads the provider's name.\n\n```\nuse majordomus_cli::evidence::RunRef;\n\nlet actions = |k: &str| {\n let v = match k {\n \"GITHUB_ACTIONS\" => \"true\",\n \"GITHUB_SERVER_URL\" => \"https://github.com\",\n \"GITHUB_REPOSITORY\" => \"owner/repo\",\n \"GITHUB_RUN_ID\" => \"42\",\n \"GITHUB_RUN_ATTEMPT\" => \"2\",\n \"GITHUB_WORKFLOW\" => \"validate\",\n \"GITHUB_JOB\" => \"evidence\",\n _ => return None,\n };\n Some(v.to_string())\n};\nlet run = RunRef::from_env(actions).unwrap();\nassert_eq!(run.id, \"42\");\nassert_eq!(run.attempt, 2);\nassert_eq!(run.url, \"https://github.com/owner/repo/actions/runs/42/attempts/2\");\n// a run that names neither its pull request's head nor its event still names itself\nassert_eq!((run.head_sha, run.event), (None, None));\n\nlet head = \"0123456789abcdef0123456789abcdef01234567\";\nlet pull = |k: &str| match k {\n \"MJ_RUN_HEAD_SHA\" => Some(head.to_string()),\n \"GITHUB_EVENT_NAME\" => Some(\"pull_request\".to_string()),\n _ => actions(k),\n};\nlet run = RunRef::from_env(pull).unwrap();\nassert_eq!(run.head_sha.as_deref(), Some(head));\nassert_eq!(run.event.as_deref(), Some(\"pull_request\"));\n\n// outside a run there is nothing to name, and a half-described run is not a run\nassert!(RunRef::from_env(|_| None).is_none());\nassert!(RunRef::from_env(|k| (k == \"GITHUB_ACTIONS\").then(|| \"true\".to_string())).is_none());\n```",
"properties": {
"attempt": {
"description": "Which attempt of the run, counted from 1.",
"format": "uint32",
"minimum": 0,
"type": "integer"
},
"event": {
"description": "The event that started the run: `push`, `pull_request`, `schedule`,\n`workflow_dispatch`.",
"type": [
"string",
"null"
]
},
"head_sha": {
"description": "The pull request's head commit when the run was a pull-request run (its `commit` is\nGitHub's merge commit, the tree that ran). Carried beside the commit, never\nsubstituted for it.",
"type": [
"string",
"null"
]
},
"id": {
"description": "The provider's identifier of the run.",
"type": "string"
},
"job": {
"description": "The job within the run that recorded the execution.",
"type": "string"
},
"provider": {
"description": "The provider that ran it, as the adapter that recorded it names it.",
"type": "string"
},
"url": {
"description": "Where a reader finds the run, as the provider addressed it at the time.",
"type": "string"
},
"workflow": {
"description": "The workflow the run belongs to.",
"type": "string"
}
},
"required": [
"provider",
"id",
"attempt",
"workflow",
"job",
"url"
],
"type": "object"
},
"EvidenceRunner": {
"description": "Which runner produced a result, and therefore how the test is named and re-run.\n\nThe repository has exactly two that a claim may name today. A third would be a variant\nhere and a branch in `TestId::of`; a claim naming something neither runner produces is\nreported as `ProofState::Unrunnable` rather than silently counted as covered.\n\n```\nuse majordomus_cli::evidence::{Runner, TestId};\n\n// which runner owns a test is read off where the test lives, never declared\nassert_eq!(TestId::of(\"test/cases/07_scope.sh\").unwrap().runner, Runner::Suite);\nassert_eq!(\n TestId::of(\"apps/majordomus-cli/tests/why.rs\").unwrap().runner,\n Runner::Crate\n);\n// and a path under neither directory belongs to no runner at all\nassert!(TestId::of(\"test/lib.sh\").is_none());\n```\n# Example\n\n```\nuse majordomus_cli::evidence::Runner;\nassert_eq!(Runner::Suite.prefix(), \"suite\");\nassert_eq!(Runner::Crate.prefix(), \"crate\");\n```",
"oneOf": [
{
"const": "suite",
"description": "A behavioural case under `test/cases/`, run by `test/run.sh`.",
"type": "string"
},
{
"const": "crate",
"description": "An integration test binary under `apps/majordomus-cli/tests/`, run by `cargo test`.",
"type": "string"
}
]
},
"ProofState": {
"description": "What the repository can say about one claim's proof, right now.\n\nOrdered from strongest to weakest, so a summary that sorts by this reads as a ranking.\n\n```\nuse majordomus_cli::evidence::ProofState;\n\nlet mut states = vec![ProofState::NotRun, ProofState::Stale, ProofState::Proven];\nstates.sort();\nassert_eq!(\n states,\n vec![ProofState::Proven, ProofState::Stale, ProofState::NotRun]\n);\n\n// the two strongest are deliberately not one state: `inputs unchanged` is the absence\n// of a known invalidation, and collapsing it into `proven` is the unaccountable badge\nassert_ne!(ProofState::Proven, ProofState::InputsUnchanged);\nassert!(ProofState::Proven < ProofState::InputsUnchanged);\nassert!(ProofState::InputsUnchanged.passing());\n```\n# Example\n\n```\nuse majordomus_cli::evidence::ProofState;\nassert!(ProofState::Proven.passing());\nassert!(!ProofState::NotRun.passing());\nassert!(!ProofState::InputsUnchanged.meaning().is_empty());\n```",
"oneOf": [
{
"const": "proven",
"description": "A passing run, and nothing has changed since it — the diff against the execution's\nown commit is empty but for the ledger. Proof of the tree in front of you.",
"type": "string"
},
{
"const": "inputs_unchanged",
"description": "A passing run, and nothing this claim names has changed since. Not proof at HEAD:\nsomething the claim does not name may have broken it.",
"type": "string"
},
{
"const": "stale",
"description": "A passing run, but something this claim names has changed since. The proof is older\nthan its subject.",
"type": "string"
},
{
"const": "failing",
"description": "The latest run of this claim's test did not pass.",
"type": "string"
},
{
"const": "not_run",
"description": "The claim names a test a runner owns, and no run of it has ever been recorded.",
"type": "string"
},
{
"const": "unrunnable",
"description": "The claim names a path no runner in this repository drives. Nothing can record it,\nso nothing can prove it this way.",
"type": "string"
},
{
"const": "no_test",
"description": "The claim names no test at all. Correct for a `planned` or `rejected` claim, and a\ndefect for any other.",
"type": "string"
}
]
}
},
"description": "One claim with everything the repository can say about its proof, and the way back out\nto the test that carries it.\n\nThe proof is flattened in, so a client reads one claim rather than an evidence wrapper\naround one; the executions and the other claims the same test proves sit beside it.\n\n```\nuse majordomus_cli::capability::builtin::evidence::ClaimEvidence;\nuse majordomus_cli::evidence::ClaimProof;\n\nlet proof: ClaimProof = serde_json::from_value(serde_json::json!({\n \"id\": \"evidence-both-directions\",\n \"claim\": \"a claim and its test answer for each other\",\n \"status\": \"guaranteed\",\n \"source\": null,\n \"implementation\": null,\n \"test_path\": \"test/cases/84_distribution_model.sh\",\n \"test\": \"suite:84_distribution_model\",\n \"state\": \"not_run\",\n \"meaning\": \"no run of this test has been recorded\",\n \"execution\": null,\n \"changed\": [],\n \"reproduce\": \"bash test/run.sh 84_distribution_model\"\n}))\n.unwrap();\n\nlet answer = ClaimEvidence {\n proof,\n executions: Vec::new(),\n also_proves: vec![\"evidence-record-is-not-networked\".to_string()],\n};\nlet json = serde_json::to_value(&answer).unwrap();\nassert_eq!(json[\"id\"], \"evidence-both-directions\");\nassert!(json.get(\"proof\").is_none(), \"the claim is flattened in, not nested\");\nassert_eq!(json[\"also_proves\"], serde_json::json!([\"evidence-record-is-not-networked\"]));\n// a list even where the ledger keeps one: retention is a decision that may change,\n// and a client that read a bare object would break when it did\nassert_eq!(json[\"executions\"], serde_json::json!([]));\n```",
"properties": {
"also_proves": {
"description": "The other claims the same test proves. A test shared by twelve claims is a test\nwhose failure is twelve findings, and a reader of one of them should be able to see\nthe other eleven without searching.",
"items": {
"type": "string"
},
"type": "array"
},
"changed": {
"description": "The files this claim names that differ between the recorded commit and the working\ntree. Empty unless the state is `ProofState::Stale`.\n\nAlways emitted, empty included: the schema this capability publishes says the key is\nthere, and a client that has to tell \"no files changed\" from \"the server did not say\"\nis a client reading two different answers as one.",
"items": {
"type": "string"
},
"type": "array"
},
"claim": {
"description": "The claim sentence.",
"type": "string"
},
"detail": {
"description": "Why the state is what it is, in one sentence, when the state alone does not say: a\ntest that declined to run, a run on a commit the presented revision does not\ncontain, a tree that was not its commit, a failing run the checkout holds uncommitted.",
"type": [
"string",
"null"
]
},
"execution": {
"anyOf": [
{
"$ref": "#/$defs/EvidenceExecution"
},
{
"type": "null"
}
],
"description": "The execution the state was derived from, when there is one."
},
"executions": {
"description": "Every execution the ledger holds for this claim's test — today one, the latest, and\na list because the ledger's retention is a decision that may change and a client\nthat read a bare object would break when it did.",
"items": {
"$ref": "#/$defs/EvidenceExecution"
},
"type": "array"
},
"id": {
"description": "The claim's id, as `docs/CLAIMS.yaml` spells it.",
"type": "string"
},
"implementation": {
"description": "The file that implements it.",
"type": [
"string",
"null"
]
},
"meaning": {
"description": "That state, in one sentence.",
"type": "string"
},
"reproduce": {
"description": "The command that produces the proof again, when a runner owns the test.",
"type": [
"string",
"null"
]
},
"source": {
"description": "The document that defines the behaviour.",
"type": [
"string",
"null"
]
},
"state": {
"$ref": "#/$defs/ProofState",
"description": "What the repository can say about the proof."
},
"status": {
"description": "The status the claim declares: `guaranteed`, `advisory`, `planned`, `rejected`.",
"type": "string"
},
"test": {
"description": "The test's stable identity, when a runner owns it.",
"type": [
"string",
"null"
]
},
"test_path": {
"description": "The path the claim names as its test, verbatim.",
"type": [
"string",
"null"
]
}
},
"required": [
"id",
"claim",
"status",
"state",
"meaning",
"changed",
"executions",
"also_proves"
],
"title": "ClaimEvidence",
"type": "object"
}Politiky
- benchmark
- povinné — cíl na každém transportu, který expozice deklaruje; případy jsou ty ze vstupního typu
- cache
- checkout — až 32 položek v procesu, vymezených otiskem registru, čtením repozitáře kontextem a stavem checkoutu (HEAD, index, refy, každá změněná cesta)
Cíle benchmarku
Odvozeno z registru pro tento repozitář: jeden požadavek na transport a případy, které poskytuje typ vstupu. Celá matice je na stránce měření výkonu.
| transport | state | případy | targets |
|---|---|---|---|
| direct | pokryto | 1 | first-claim studený+teplý |
| mcp | pokryto | 1 | first-claim studený+teplý |
| http | pokryto | 1 | first-claim studený+teplý |
Tvrzení implementovaná vedle ní
Připojeno souborem, který každé tvrzení implementuje; každé odkazuje na svou stránku s implementací a testem, který je dokazuje.