Worked example: an investigation
Generated from fixtures/investigation/protocol.yaml by running Canon's own parser, validator and compiler over it. The protocol is deliberately not about software: Canon is meant to express any evidence-governed undertaking, and this is the fixture Canon's own tests use.
Decide whether an explanation is supported by observation and survives an attempt to falsify it.
The protocol
format: protocol/1
protocol:
id: investigation
revision: 1
description: Decide whether an explanation is supported by observation and survives an attempt to falsify it.
artifacts:
explanation:
description: The explanation under investigation.
evidence_kinds:
supporting_observation:
description: An observation consistent with the explanation.
falsification_attempt:
description: An attempt to refute the explanation; its result is survived or refuted.
claims:
explanation.supported:
description: The explanation is supported by observation and has survived falsification.
true_when:
all:
- evidence:
kind: supporting_observation
- evidence:
kind: falsification_attempt
result: survived
actions:
inspect:
description: Look for observations bearing on the explanation.
may_produce:
- evidence: supporting_observation
attempt_falsification:
description: Try to refute the explanation.
may_produce:
- evidence: falsification_attempt
outcomes:
supported:
description: The explanation is supported.
requires:
claim: explanation.supported
What it declares
Protocol investigation at revision 1.
Artifacts
| Artifact | Description |
|---|---|
explanation | The explanation under investigation. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Evidence kinds
| Evidence kind | Description |
|---|---|
supporting_observation | An observation consistent with the explanation. |
falsification_attempt | An attempt to refute the explanation; its result is survived or refuted. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Claims
| Claim | True when | Description |
|---|---|---|
explanation.supported | all of: evidence of kind supporting_observation; evidence of kind falsification_attempt with result survived | The explanation is supported by observation and has survived falsification. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Obligations
None declared.
Actions
| Action | Precondition | Requires authority for | Effect | May produce | Description |
|---|---|---|---|---|---|
inspect | none: always applies | none | none | supporting_observation | Look for observations bearing on the explanation. |
attempt_falsification | none: always applies | none | none | falsification_attempt | Try to refute the explanation. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Outcomes
| Outcome | Requires | Description |
|---|---|---|
supported | claim explanation.supported is true | The explanation is supported. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Validation
canon validate --path fixtures/investigation/protocol.yaml accepts it: the validator reports no problem. See validation for what it checks.
The compiled form
canon compile --path fixtures/investigation/protocol.yaml prints its canon-ir/1:
{
"actions": {
"attempt_falsification": {
"description": "Try to refute the explanation.",
"effect": null,
"may_produce": [
{
"evidence": "falsification_attempt"
}
],
"precondition": {
"all": []
},
"requires": []
},
"inspect": {
"description": "Look for observations bearing on the explanation.",
"effect": null,
"may_produce": [
{
"evidence": "supporting_observation"
}
],
"precondition": {
"all": []
},
"requires": []
}
},
"artifacts": {
"explanation": {
"description": "The explanation under investigation."
}
},
"claims": {
"explanation.supported": {
"description": "The explanation is supported by observation and has survived falsification.",
"true_when": {
"all": [
{
"evidence": {
"kind": "falsification_attempt",
"result": "survived"
}
},
{
"evidence": {
"kind": "supporting_observation",
"result": null
}
}
]
}
}
},
"evidence_kinds": {
"falsification_attempt": {
"description": "An attempt to refute the explanation; its result is survived or refuted."
},
"supporting_observation": {
"description": "An observation consistent with the explanation."
}
},
"format": "canon-ir/1",
"obligations": {},
"outcomes": {
"supported": {
"description": "The explanation is supported.",
"requires": {
"claim": {
"id": "explanation.supported",
"is": "true"
}
}
}
},
"protocol": {
"description": "Decide whether an explanation is supported by observation and survives an attempt to falsify it.",
"id": "investigation",
"revision": 1
}
}
Evaluating a case
canon evaluate reads the compiled protocol, a canon-case/1 snapshot and a directory of canon-evidence/1 records, and prints a canon-decision/1 document. These values are computed by Canon's evaluator for the case below; see evaluation for the rules.
format: canon-case/1
id: INV-18
protocol: investigation
artifacts:
explanation:
revision: r1
| Evidence on record | Value |
|---|---|
| Nothing yet | explanation.supported is unknown |
| A supporting observation only | explanation.supported is unknown |
| A supporting observation, and a falsification attempt the explanation survived | explanation.supported is true |
| A supporting observation, and a falsification attempt that refuted it | explanation.supported is false |
| A supporting observation, and two falsification attempts that disagree | explanation.supported is unknown |
More columns: swipe horizontally, or focus the table and use the arrow keys.
With a supporting observation and a falsification attempt the explanation survived, the evidence directory holds these two records:
format: canon-evidence/1
id: obs-1
kind: supporting_observation
subject: explanation
subject_revision: r1
format: canon-evidence/1
id: fal-1
kind: falsification_attempt
result: survived
subject: explanation
subject_revision: r1
and canon evaluate --ir investigation.ir.json --case case.yaml --evidence evidence/ prints:
{
"actions": {
"attempt_falsification": {
"status": "admissible"
},
"inspect": {
"status": "admissible"
}
},
"case": "INV-18",
"claims": {
"explanation.supported": {
"value": "true"
}
},
"explanation": {
"computed_from": {
"case": {
"artifacts": {
"explanation": {
"revision": "r1"
}
},
"format": "canon-case/1",
"id": "INV-18",
"protocol": "investigation"
},
"evidence": [
"fal-1",
"obs-1"
],
"protocol": "investigation",
"protocol_revision": 1,
"semantics": {
"canon": "0.9.0",
"format": "canon-decision/1"
}
}
},
"format": "canon-decision/1",
"outcomes": {
"supported": {
"status": "legitimate"
}
},
"protocol": "investigation",
"protocol_revision": 1
}
Besides the claims, the decision gives each declared action admissible, approval-required or blocked under the authority decisions given (none here), and each declared outcome legitimate or blocked. This protocol declares no obligation, so the decision has no obligations section. See evaluation for each section. Both records are bound to explanation at its current revision; a record bound to any other revision would be listed under the claim as excluded and would not count.
Broken variants
The repository keeps broken copies of this protocol in fixtures/investigation/invalid. Each is rejected; these are the problems the validator reports for them.
| Variant | Code | Problem |
|---|---|---|
case-open-self.yaml | self-opened-case | action reaudit opens a case under protocol audit, the protocol's own id |
duplicate-identifier.yaml | duplicate-identifier | action inspect is declared more than once |
input-duplicate-value.yaml | duplicate-input-value | input severity lists value low more than once |
input-empty-values.yaml | empty-input-values | input urgency declares no value |
input-test-duplicate-value.yaml | duplicate-input-test-value | obligation peer.review tests input severity for value high more than once |
input-test-empty.yaml | empty-input-test | obligation peer.review tests input severity for no value |
input-undeclared-value.yaml | undeclared-input-value | obligation peer.review tests input severity for value critical, which the input does not declare |
input-undeclared.yaml | undeclared-input | action publish_finding references input urgency, which is not declared |
undeclared-claim.yaml | undeclared-claim | outcome supported references claim explanation.refuted, which is not declared |
undeclared-discharge-claim.yaml | undeclared-claim | obligation establish.explanation references claim explanation.refuted, which is not declared |
undeclared-evidence-kind.yaml | undeclared-evidence-kind | action attempt_falsification references evidence kind expert_opinion, which is not declared |
More columns: swipe horizontally, or focus the table and use the arrow keys.