Concepts · 4 of 7
Step order
Order between steps comes from preconditions and evidence order now, and from revision order later.
A protocol has no workflow states. Order between steps comes from what each action and outcome needs. A bug fix should show red before the fix and green after it; decision record 0084 settles how protocols say so, in three steps.
Shipped · runs today
- ShippedOrdering by action preconditionCanon evaluation reports an action blocked while its precondition is not TRUE.
- ShippedRed first for a bugfixsoftware.change/1: implementation.edit needs regression.reproduced when the case's change_kind is bugfix.
- ShippedEvidence bound to the current revisionCanon excludes evidence recorded for another revision of its subject.
- ShippedEvidence-order predicateCanon 0.3.0: first and before. software.change/1 reads red first as a first regression test result that failed, before the first recorded implementation change.
Decided · recorded, not built
- DecidedRevision-order relationRed on R1, green on R2 descended from R1, same test. Later; needs a revision-relation construct.
- DecidedPath scope on capabilitiesTells test edits from code edits. The scope field of decision record 0083; not in Canon yet.
Now: preconditions
In software.change/1, editing the repository is two actions. Writing tests, tests.write, has no
precondition. Changing the implementation, implementation.edit, needs the case to be a feature or
a refactor, or the claim regression.reproduced. A failing test result about the current
implementation revision establishes it, and so does a regression test whose first result, on any
revision, was a failure. The case says which kind of change it is in its change_kind input when
it opens. An agent asking for implementation.edit on a bugfix before red exists gets "blocked",
with the claim and the input that block it as the reasons.
case:
inputs:
change_kind:
values: [feature, bugfix, refactor]
claims:
regression.reproduced:
true_when:
any:
- evidence: {kind: test_result, result: fail, subject: implementation}
- first: {kind: regression_test_result, result: fail, subject: implementation}
regression.shown_first:
true_when:
all:
- first: {kind: regression_test_result, result: fail, subject: implementation}
- before: {first: regression_test_result, then: implementation_change, subject: implementation}
obligations:
red_first.required:
applicable_when: {input: change_kind, in: [bugfix]}
discharged_when: {claim: regression.shown_first}
actions:
tests.write:
effect: write # no precondition
implementation.edit:
effect: write
precondition:
any:
- {input: change_kind, in: [feature, refactor]}
- claim: regression.reproduced # a bugfix waits for red
Neither action names a capability yet: telling a test edit from an implementation edit needs a path
scope on capabilities, which Canon does not have. Hover implementation.edit in the graph to see the
precondition that gates it. The graph draws the order forms too: hover regression.shown_first to
see its first and before, and its edges from regression_test_result and
implementation_change.
Protocol · revision 1
software.change/1Deliver a change to a software system: implement it, verify the current implementation revision, merge it under authority, release and deploy it, and accept it once its objective is realized; or close it declined, superseded or abandoned on an explicit decision, or rolled back on a complete rollback result. A case fixes its risk, which selects the obligations that apply, and its change kind, which selects whether a regression must be reproduced before the implementation is edited, and whether its regression test must fail on its first run, before the implementation is first changed; and whether it affects a security boundary, in which case the implementation is verified only once a principal other than the implementer approved its security review. A deployment is healthy only on an observation at most 30 minutes old.
- Actions6
- Evidence kinds9
- Claims9
- Outcomes5
- Obligations6
- Claim supports claim
- Precondition, traced on hover
- Needs authority
Hover or focus a node to trace what it rests on and what rests on it. Press Enter to pin it, Escape to clear.
Case inputs
affects_security_boundaryfalsetruewhether the change affects a security boundary; one that does needs an approving security review from a principal other than the implementer before its implementation is verifiedchange_kindbugfixfeaturerefactorwhat the change is; a bugfix must reproduce its regression with a failing test before the implementation is edited, and its regression test must fail on its first run, before the implementation is first changedriskcriticalelevatedstandardtrivialhow much proof the change must carry; each level applies every obligation of the level below it and one more
Protocol as text
| Name | Description | Rule | Leads to |
|---|---|---|---|
implementation.edit | change the implementation in the repository's working revision; a bugfix needs its regression reproduced first | any of claim regression.reproduced input change_kind in feature, refactor effect write | produces implementation_change |
release.rollback | return to a previous release; needs authority to roll back, and invoking it earns no outcome until a rollback result says it is complete | needs release.rollback effect write | produces rollback_result |
repository.inspect | read the repository | effect read | — |
repository.merge | merge a revision into the repository's mainline; needs the current implementation revision verified and authority to merge, never only a connection to the repository host | claim implementation.verified needs repository.merge effect write | — |
tests.run | run the tests against an implementation revision | effect read | produces regression_test_result; produces test_result |
tests.write | change the tests in the repository's working revision | effect write | — |
More columns: swipe horizontally, or focus the table and use the arrow keys.
| Name | Description | Rule | Leads to |
|---|---|---|---|
build_provenance | the record of how a release was built from an implementation | — | establishes release.proven (about release) |
code_review | a review of an implementation revision; its result is approved or rejected | — | establishes implementation.reviewed (approved about implementation) |
implementation_change | the record that the implementation was changed, moving it to a new revision | — | establishes regression.shown_first (after regression_test_result about implementation) |
objective_observation | an observation of whether the intent's objective is met; its result is satisfied or unsatisfied | — | establishes objective.realized (satisfied about intent) |
operational_observation | an observation of the running system; its result is healthy or unhealthy, and it applies for 30 minutes after it is observed, after which it no longer says anything | — | establishes deployment.healthy (healthy about deployment) |
regression_test_result | the result of running a bugfix's regression test against an implementation revision; its result is pass or fail | — | establishes regression.reproduced (first fail about implementation); establishes regression.shown_first (before implementation_change about implementation); establishes regression.shown_first (first fail about implementation) |
rollback_result | the result of returning a release to the one before it; its result is complete or partial | — | — |
security_review | a review of an implementation revision's effect on a security boundary; its result is approved or rejected | — | establishes security.reviewed (approved about implementation, independent on different_principal) |
test_result | the result of running tests against an implementation revision; its result is pass or fail | — | establishes implementation.verified (pass about implementation); establishes regression.reproduced (fail about implementation); establishes tests.pass (pass about implementation) |
More columns: swipe horizontally, or focus the table and use the arrow keys.
| Name | Description | Rule | Leads to |
|---|---|---|---|
deployment.healthy | the deployment is running healthily | evidence = healthy: operational_observation | requires accepted; requires health.required |
implementation.reviewed | the current implementation revision is reviewed | evidence = approved: code_review | requires review.required |
implementation.verified | the current implementation revision is verified: its tests pass and, when the change affects a security boundary, it is security reviewed | all of any of claim security.reviewed input affects_security_boundary in false evidence = pass: test_result | supports release.proven; gates repository.merge |
objective.realized | the intent's objective is met | evidence = satisfied: objective_observation | requires accepted |
regression.reproduced | the regression a bugfix repairs is reproduced: a test has failed on the current implementation revision, or the first run of the regression test, on any revision of the implementation, failed | any of evidence = fail: test_result first evidence = fail: regression_test_result about implementation | gates implementation.edit |
regression.shown_first | the regression test failed first, before the implementation was first changed: the first regression test result about the implementation failed, and it was observed before the implementation's first change | all of evidence regression_test_result before implementation_change about implementation first evidence = fail: regression_test_result about implementation | requires red_first.required |
release.proven | the current implementation revision is verified and the current release revision carries build provenance; nothing here ties that release to the verified implementation revision | all of claim implementation.verified any evidence: build_provenance | requires accepted; requires provenance.required |
security.reviewed | the current implementation revision's security review is approved by a producer the case lists as another principal than the implementer | evidence = approved: security_review | supports implementation.verified; requires security_review.required |
tests.pass | the tests pass for the current implementation revision | evidence = pass: test_result | requires tests.required |
More columns: swipe horizontally, or focus the table and use the arrow keys.
| Name | Description | Rule | Leads to |
|---|---|---|---|
abandoned | the case closed because the change was explicitly abandoned without reaching any planned outcome | — | — |
accepted | the case closed with its result accepted; needs the release proven, the deployment healthy and the objective realized | all of claim deployment.healthy claim objective.realized claim release.proven | — |
declined | the case closed because the change was explicitly declined; needs no implementation | — | — |
rolled_back | the case closed with its release rolled back; needs a rollback result about the current release revision that says the rollback is complete | evidence = complete: rollback_result | — |
superseded | the case closed because another change explicitly superseded it | — | — |
More columns: swipe horizontally, or focus the table and use the arrow keys.
| Name | Description | Rule | Leads to |
|---|---|---|---|
health.required | the deployment is healthy; applies at critical risk | applicable when input risk in critical claim deployment.healthy | — |
provenance.required | the release is proven; applies at elevated risk and above | applicable when input risk in critical, elevated claim release.proven | — |
red_first.required | the regression test failed on its first run, before the implementation was first changed; applies to a bugfix, at every risk | applicable when input change_kind in bugfix claim regression.shown_first | — |
review.required | the current implementation revision is reviewed; applies at standard risk and above | applicable when input risk in critical, elevated, standard claim implementation.reviewed | — |
security_review.required | the current implementation revision is security reviewed by another principal than the implementer; applies to a change that affects a security boundary, at every risk | applicable when input affects_security_boundary in true claim security.reviewed | — |
tests.required | the tests pass for the current implementation revision; applies at every risk | applicable when input risk in critical, elevated, standard, trivial claim tests.pass | — |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Source: protocols/software-change/1.yaml
Now: evidence order
Canon 0.3.0 orders evidence by when it was observed. first asks whether the first record of a kind
has a result; before asks whether the first record of one kind was observed before the first
record of another. Both read the whole history, records about earlier revisions included, so they
say what happened in what order, not what holds of the current revision.
software.change/1 tells the bugfix's regression test apart from the suite by kind: tests.run
may produce a test_result or a regression_test_result, and implementation.edit may produce an
implementation_change. A bugfix that runs the suite green on R1, writes its regression test and
runs it red on R1 has reproduced its regression, and may edit. The edit moves the implementation to
R2, and the red run, about R1, still counts: it is the first regression test result. A fix that
needs a second edit makes it without running red again.
The obligation red_first.required applies to every bugfix and is discharged once
regression.shown_first holds: the first regression test result about the implementation failed,
and it was observed before the implementation's first change. An edit made before any regression
test ran leaves it open for good, and so does a regression test whose first result passed, even
when it ran before the edit and a failing suite run admitted the edit.
What the protocol still cannot say
Canon does not know how revisions descend. A red record about any earlier revision counts, whether or not the current revision descends from it. Records without an observation time have no place in the order, and leave both forms unknown.
The rule sees a change to the implementation only through its record: implementation.edit may
produce an implementation_change, but need not, and before reads only the records there are. A
change made without that record is not seen, so a revision moved that way before the first red run
does not count as the first change, and the obligation can still be discharged.
The suite's own path is unchanged: a failing test_result about the current revision reproduces
the regression, a pass and a fail of one kind on one revision contradict each other, and a failure
on an unrelated flake satisfies it. Nothing yet says that the failing test is a test of the change.
| Gap | Closed by | Status |
|---|---|---|
| The failing result must come before the fix | the evidence-order forms: the first regression_test_result is fail, and it precedes the first recorded implementation_change | shipped |
| Red and green must be about the same test, across the fix | revision order: red on revision R1 (test added, fix absent), green on R2 descended from R1, same test id | decided, later |
| A test edit must not touch the implementation | a path scope on capabilities that tests.write and implementation.edit would require | decided, not built |
| The red result must come from the test runner, not the agent | evidence independence: Canon 0.4.0's independent_on on an evidence match, which software.change/1 demands of its security review but of no test result | decided, not applied |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Until those land, the order is enforced at the moment an action is invoked (the agent cannot edit the
implementation before red exists) and recorded as the red_first.required obligation, and the rest
is reviewed.
Profiles
The red-first rule belongs to bug fixes, not to every change. It is the bugfix profile of
software.change/1: the value bugfix of the case input change_kind. A refactor omits it, and so
does a feature for now. See Profiles and generated protocols.