Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@ neither can tell you that a behavior quietly stopped matching what it was for.

| Layer | | Status |
|---|---|---|
| **Behavior** | the Flow graph, evidence, impact, erosion detection | **works today** — v0.1, modelled against itself in CI |
| **Outcome** | an outcome carrying runtime evidence, able to refute a claim | **not built** — the layer that would detect a *wrong* claim rather than a stale one |
| **Intent** | a behavior citing the frozen decision that asked for it | **not built** — verified by provenance, never by truth |
| **Behavior** | the Flow graph, evidence, impact, erosion detection | **works** — modelled against itself in CI |
| **Outcome** | an outcome names the check that says whether it occurred; a `refutes` there is an **error** | **mechanism works, value unproven** — INV-027, the only place reality can contradict the model |
| **Intent** | a flow cites the frozen decision that asked for it, verified by provenance | **mechanism works, value unproven** — INV-028, citing the ADRs you already write rather than adding a format |

"Value unproven" is not modesty. The mechanism is built, tested and enforced; what has
**not** been run is the measurement that would justify it — take three incidents that
actually happened and ask whether this would have caught any before they became one.
That kill condition is written down in
[ADR-015](docs/decisions/015-intent-behavior-outcome.md) and has not been answered.

The direction, the four horizons and the measurement that would kill each of them are in
[`docs/DIRECTION.md`](docs/DIRECTION.md). Nothing on that page is claimed as shipped.
Expand Down
21 changes: 19 additions & 2 deletions docs/DIRECTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,14 @@ what it excluded (INV-025).
*Kills it:* erosion fires often enough on a healthy repository to be tuned out. Unmeasured
— #10 is the number, and no horizon past this one is worth starting before it exists.

### H2 — Outcome carries evidence
### H2 — Outcome carries evidence — *mechanism built, value unproven*

**Built (INV-027).** An Outcome names the Assertion that checks whether it occurred, or is
reported as declaring none. A `refutes` on that check raises `OUTCOME_REFUTED` at error
level and takes integrity to INVALID. What was missing was never the `runtime` evidence
kind — it was anything that treated a refuted outcome differently from a stale reference.

**Not built, and not a coding task:** the proof that it catches anything.

Outcome today is `declared` and nothing else (INV-015): pure AUTHORED. It gains evidence
the way an Assertion has evidence, including a `runtime` kind whose observation is the
Expand All @@ -83,7 +90,17 @@ the invariant currently conflates them.
whether this mechanism would have caught any before they became incidents. **0 of 3 and
the direction is vocabulary, not capability.**

### H3 — Intent as provenance, never as truth
### H3 — Intent as provenance, never as truth — *built*

**Built (INV-028).** An Intent cites a frozen record (§6.2.1); `realizes:` on a Flow names
the Intents it serves; `check_locators` checks that record's address like any other, so a
decision whose record was moved or rewritten stops resolving. `FLOW_WITHOUT_INTENT` is
reported at `info` and never gates.

**Deliberately not built:** any format for the record. Research before building — ADRs,
closed issues and commit trailers already exist with conventions and tooling, and what the
ecosystem lacks is not another decision format but anything that notices when an accepted
decision has stopped matching the behavior.

An Intent entity whose evidence is a **frozen record** (§6.2.1) — an ADR, a closed issue,
a commit message, a decision minute. Verification is provenance: *is this the record that
Expand Down
103 changes: 100 additions & 3 deletions docs/semantic-specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,46 @@ The validator MUST warn and MUST NOT silently promote a terminal node to an Outc

---

### 4.6 Intent — INV-028

An **Intent** says why a behavior was asked for. A Flow declares the Intents it serves
with `realizes:`.

```yaml
intents:
- id: intent.confidence-must-be-able-to-fall
statement: >-
Confidence has to drop without anyone editing the model, or the model records
only that somebody was once confident.
record: { kind: decision, locator: "docs/decisions/003-confidence-is-derived.md#Decision" }
```

**INV-028 INTENT-IS-PROVENANCE.** An Intent is verified by provenance, never by truth.

Nothing can establish that a sentence is genuinely why something was built. What *can*
be established is whether the Intent names the **frozen record** that asked for it
(§6.2.1), whether that record still resolves, and whether it has been superseded. Those
are the only questions this layer answers, and the spec says so rather than letting a
reader infer more from a green check.

A model that tried to verify Intent by reading the code would be circular: the code is
the thing the Intent is supposed to explain.

**TraceOS defines no format for the record.** Architecture decision records, closed
issues and commit trailers already exist, with established conventions and tooling to
author and supersede them. What did not exist is anything that notices when an accepted
decision has stopped matching the behavior — and a citation that stops resolving is the
cheapest available signal of exactly that.

Supersession reuses the identity ledger unchanged (INV-014): a decision replaced by a
later decision is a `supersedes` with a reason, which is what an ADR's own
"superseded by" line already means.

`FLOW_WITHOUT_INTENT` is reported at `info` and never gates. Most behavior in a real
system predates anyone writing the decision down, and a gate that demanded otherwise
would be satisfied by invented intents — which is worse than none, for the same reason a
rubber-stamped observation is worse than a missing one (§13.0.1).

## 5. Relationships

### 5.1 The matrix — INV-006
Expand Down Expand Up @@ -509,9 +549,14 @@ The lifecycle was mislabelled; the resolver is not missing anything.

### INV-018 NO-HEALTH

Runtime health is out of scope for v0.1. TraceOS asks *what is the system's
behavior*; health asks *is the running system healthy*. Uptime, latency, CPU, memory,
availability and incident state belong to monitoring, which §Non-goals excludes.
Runtime health is out of scope. TraceOS asks *what is the system's behavior*; health
asks *is the running system healthy*. Uptime, latency, CPU, memory, availability and
incident state belong to monitoring, which §Non-goals excludes.

This invariant once carried a second question it should not have: *did the outcome this
model declares actually occur*. That is verification, not monitoring, and §6.4.1 draws
the line — the subject decides. Behavior evidenced by a runtime artifact is evidence;
the machine's condition is not behavior.

Two judgement scales remain, both DERIVED:

Expand Down Expand Up @@ -1052,6 +1097,56 @@ a symbol whose file had moved 21 times and whose symbol had moved once. The rema
were re-observation requests for code the change never touched, which is the material a
rubber stamp is made of (§13.0.1).

### 6.4 An Outcome declares how it is checked — INV-027

**INV-027 OUTCOME-DECLARES-ITS-CHECK.** An Outcome names the Assertion that checks
whether it occurred, or it is reported as declaring none.

```yaml
outcomes:
- { id: purchase.completed,
states: [{ subject: order, value: confirmed }],
verified_by: assert.purchase.confirms-order }
```

**This is the only place in the model where reality can contradict it.** Intent and
Behavior are both statements, and two statements can disagree only about words. An
Outcome can be measured. So an observation that `refutes` an Outcome's check is the
first machine-produced evidence that a claim is **wrong** rather than merely **stale** —
which is the distinction every other mechanism in this specification is unable to make.

| Finding | Level | Means |
|---|---|---|
| `OUTCOME_REFUTED` | error | the model says this outcome occurs; its own check says it did not |
| `OUTCOME_CHECK_UNKNOWN` | error | `verified_by` names an Assertion this model does not have |
| `OUTCOME_NEVER_CHECKED` | warn | a check is named and has never been observed |
| `OUTCOME_NOT_VERIFIABLE` | warn | no check is declared |

An Outcome with no check is reported, never failed. What is forbidden is silence: an
unverifiable Outcome and a verified one must not read the same (INV-025).

#### 6.4.1 What this does and does not admit about runtime

INV-018 keeps runtime **health** out of scope permanently — uptime, latency, CPU,
memory, availability and incident state belong to monitoring. That has not changed.

What INV-027 admits is a different question, which INV-018 previously conflated with it:

| Question | Status |
|---|---|
| *is the running system healthy* | out of scope, permanently (INV-018) |
| *did the outcome this model declares actually occur* | in scope — it is verification, not monitoring |

The boundary is the subject. An assertion about **the system's behavior**, evidenced by
something a runtime produced, is evidence like any other, and `kind: runtime` has been a
legal evidence kind since v0.1. An assertion about **the system's condition** is not
behavior and does not enter.

TraceOS defines no query language for this. Reading an indicator from a data source is a
solved problem with an open specification of its own, and an Outcome's runtime evidence
cites such a definition the way an Intent cites an ADR — by locator, never by
reimplementation.

---

## Appendix A — Invariant index
Expand Down Expand Up @@ -1084,3 +1179,5 @@ rubber stamp is made of (§13.0.1).
| INV-024 | Decay must be discharged in the change that touches it | 13.0.1 |
| INV-025 | A boundary reports what it excluded; it never reports silence | 13.0.2 |
| INV-026 | A gate has three outcomes; an empty scan is not a pass | 13.0.3 |
| INV-027 | An Outcome declares the Assertion that checks it | 6.4 |
| INV-028 | Intent is verified by provenance, never by truth | 4.6 |
4 changes: 3 additions & 1 deletion examples/ecommerce/model/flows/purchase.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ relationships:
- { type: emits, source: node.purchase.confirm, target: event.order.created }
- { type: transitions_to, source: node.purchase.confirm, target: state.order.confirmed }
- { type: transitions_to, source: node.purchase.reject, target: state.order.rejected }
realizes:
- intent.a-confirmed-order-is-a-promise
outcomes:
- { id: purchase.confirmed, states: [{ subject: order, value: confirmed }] }
- { id: purchase.confirmed, states: [{ subject: order, value: confirmed }], verified_by: assert.purchase.confirms-order }
- { id: purchase.rejected, states: [{ subject: order, value: rejected }] }
assertions:
- id: assert.purchase.confirms-order
Expand Down
27 changes: 27 additions & 0 deletions examples/ecommerce/model/intents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
id: system.shop.intents
type: intents
intents:
- id: intent.a-confirmed-order-is-a-promise
statement: >-
Once an order reads CONFIRMED the customer has been told it will be fulfilled,
so nothing downstream may quietly leave it in that state without paying.
record: { kind: decision, locator: "docs/decisions/0004-order-confirmation.md#Decision" }
lifecycle: current
- id: intent.a-refund-never-outruns-the-charge
statement: >-
A refund is issued only against a settled charge, because a refund on an
unsettled one leaves money owed in both directions.
record: { kind: decision, locator: "docs/decisions/0009-refund-ordering.md#Decision" }
lifecycle: current
---

## What belongs here

Why each Flow exists, citing the frozen record that asked for it (spec 6.2.1).

Verified by **provenance, never by truth** (INV-028). The locators above point at
decision records this example repository does not ship — `check_locators` reports them
as unresolved, which is the correct and intended reading: *the citation is declared and
cannot be verified here*. That is the state most real models start in, and it is
reported rather than hidden.
5 changes: 4 additions & 1 deletion examples/traceos-itself/model/flows/reconcile.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ relationships:
- { type: interacts_with, source: node.reconcile.integrity, target: external.reader }
- { type: transitions_to, source: node.reconcile.integrity, target: state.integrity.reported }
- { type: depends_on, source: flow.reconcile, target: external.repository }
realizes:
- intent.confidence-must-be-able-to-fall
- intent.derived-is-never-authored
outcomes:
- { id: reconcile.reported, states: [{ subject: integrity, value: reported }] }
- { id: reconcile.reported, states: [{ subject: integrity, value: reported }], verified_by: assert.reconcile.integrity-is-computed }
assertions:
- id: assert.reconcile.confidence-decays
claim: "confidence falls when an artifact moves under an observation, with no model file edited"
Expand Down
4 changes: 3 additions & 1 deletion examples/traceos-itself/model/flows/render.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ relationships:
- { type: depends_on, source: node.render.compute, target: state.integrity.reported }
- { type: interacts_with, source: node.render.publish, target: external.reader }
- { type: transitions_to, source: node.render.publish, target: state.view.published }
realizes:
- intent.a-view-is-not-a-source
outcomes:
- { id: render.published, states: [{ subject: view, value: published }] }
- { id: render.published, states: [{ subject: view, value: published }], verified_by: assert.render.view-not-truth }
assertions:
- id: assert.render.no-second-implementation
claim: "every figure on the page is computed by the engine and embedded as a result, so no traversal runs in the browser"
Expand Down
4 changes: 3 additions & 1 deletion examples/traceos-itself/model/flows/trace.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ relationships:
- { type: next, source: node.trace.tier, target: node.trace.gate }
- { type: emits, source: node.trace.gate, target: event.change.traced }
- { type: transitions_to, source: node.trace.gate, target: state.impact.tiered }
realizes:
- intent.derived-is-never-authored
outcomes:
- { id: trace.tiered, states: [{ subject: impact, value: tiered }] }
- { id: trace.tiered, states: [{ subject: impact, value: tiered }], verified_by: assert.trace.four-tiers }
assertions:
- id: assert.trace.four-tiers
claim: "impact is reported in four tiers and never as a list of changed files"
Expand Down
4 changes: 3 additions & 1 deletion examples/traceos-itself/model/flows/understand.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ relationships:
- { type: next, source: node.understand.observe, target: node.understand.assert }
- { type: interacts_with, source: node.understand.observe, target: external.repository }
- { type: transitions_to, source: node.understand.assert, target: state.model.established }
realizes:
- intent.reference-is-an-address
outcomes:
- { id: understand.modeled, states: [{ subject: model, value: established }] }
- { id: understand.modeled, states: [{ subject: model, value: established }], verified_by: assert.understand.observes-before-asserting }
assertions:
- id: assert.understand.observes-before-asserting
claim: "an evidence reference is authored, then checked, and only the check is recorded"
Expand Down
45 changes: 45 additions & 0 deletions examples/traceos-itself/model/intents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
id: system.traceos.intents
type: intents
intents:
- id: intent.derived-is-never-authored
statement: >-
A value the system can compute must never be stored as something a person
wrote, because the stored copy goes stale and then lies about exactly the
property it exists to express.
record: { kind: decision, locator: "docs/decisions/001-three-tier-entities.md#Decision" }
lifecycle: current
- id: intent.confidence-must-be-able-to-fall
statement: >-
Confidence has to drop without anyone editing the model, or the model records
only that somebody was once confident.
record: { kind: decision, locator: "docs/decisions/003-confidence-is-derived.md#Decision" }
lifecycle: current
- id: intent.reference-is-an-address
statement: >-
A reference names where to look, never what was found; verification is a
separate act that must be recorded each time it happens.
record: { kind: decision, locator: "docs/decisions/002-evidence-reference-vs-observation.md#Decision" }
lifecycle: current
- id: intent.a-view-is-not-a-source
statement: >-
Anything rendered is regenerated from the model and never edited in place, so
no reader has to work out which copy is the real one.
record: { kind: decision, locator: "docs/decisions/008-artifact-is-derived.md#Decision" }
lifecycle: current
---

## What belongs here

An Intent says **why** a behavior was asked for, and cites the **frozen record**
(§6.2.1) that asked — here, this repository's own ADRs.

Intent is verified by provenance, never by truth (INV-028). The checkable questions
are *does the record still resolve* and *has it been superseded*. Whether the sentence
is genuinely the reason is not answerable by any mechanism, and a model that tried to
settle it by reading the code would be circular: the code is the thing the intent is
supposed to explain.

TraceOS adds no format for these records. ADRs, closed issues and commit trailers
already exist, with tooling to author and supersede them. What did not exist is
anything that notices when an accepted decision has stopped matching the behavior.
Loading