GoogleCloudPlatform / GoogleCloudPlatform/open-knowledge-format
Proposal: Third trust field `refuted`
- Dominant language
- HTML
- Stars
- 467
- Forks
- 35
- Avg merge
- 9m
- Merged PRs (30d)
- 1
Description
> Moved here from GoogleCloudPlatform/knowledge-catalog#345, which I filed
> against the frozen `okf/` snapshot before noticing this repository is the
> canonical home. This version fixes a defect in the tier rule that
> @leesharks000 found there (see "Tier derivation"). Thank you for pointing me
> to this repository :D
## Problem
OKF v0.2 §5.2 records two things about a concept's trust: how it was produced
(`generated`) and who confirmed it (`verified[]`). §5.3 derives the trust tier
from `verified` alone:
- no `verified` ⇒ *unverified*
- non-`human:` verifiers only ⇒ *machine-confirmed*
- any `human:` verifier ⇒ *human-reviewed*
This leaves no way to record the opposite of `verified`: someone examined the concept
and found it does not hold up to their standard. Additionaly, it cannot simply be assumed that a concept will be
deleted just because a verification fails. Right now concepts, which where not yet
verified, and concepts, which failed verification, look identical to a consumer, because both carry no `verified` key
and both land in the *unverified* tier:
1. a concept nobody has looked at yet (downstream action: examine, then
promote or reject), and
2. a concept that was checked and rejected (downstream action: replace, and
do not restore).
The correct downstream action differs in category between the two, in
the same way it differs in §5.3 between *unverified* and *human-reviewed*.
The same conceptual line has been drawn in #11 with removed vs. never-written (#11, formerly
GoogleCloudPlatform/knowledge-catalog#207). And for conflicting concepts as well with contested vs. merely uncorroborated
(GoogleCloudPlatform/knowledge-catalog#159, GoogleCloudPlatform/knowledge-catalog#195).
The failure shows up as soon as more than one actor manipulates the concepts.
A producer that knows a value is wrong has no field to store that knowledge in
the model, so it lives in a chat log, a commit message, or a person's head,
and the next actor to touch the concept starts from zero. The nearest options
all say something else:
- `status: deprecated` (§5.4) means "no longer current", not "never held";
a deprecated concept is still read as having been true once.
- `contested_by` (knowledge-catalog#195) is a symmetric edge between two
concepts that defers adjudication; it carries no verdict by design.
- Deleting the concept discloses nothing (#11), prevents correction and lets
a partner whose copy still carries the value resurrect it on the next merge
in concurrent scenarios.
With a `refuted` record in the frontmatter, three things become possible that
are not possible today:
1. A consumer can act on a failed check without re-running it. A retrieval
layer can drop the concept from in-force results, an agent can refuse to
use the value, and a UI can show "checked by X on date, does not hold"
instead of a blank. None of that needs the checker's tooling, only the
record.
2. A refutation survives the transfer between bundles. When two copies merge, the
copy carrying the refutation should win over the copy that still has the
stale value, because the refutation is an event with a timestamp, not an
absence. Today the stale copy wins by default, because absence of
`verified` on both sides looks like agreement.
3. The reason for the rejection stays with the concept. Whoever rewrites the
content later sees what was wrong with the old version and can check that
the new one does not repeat it.
`verified` communicates "someone checked this and it held" from
"nobody checked". `refuted` communicates "someone checked this and it failed"
from the same "nobody checked".
## Proposal
### Extend Trust (§5.2)
Add one optional key to the trust family, with the same shape as `verified`:
```yaml
refuted:
- { by: human:mdorn, at: 2026-08-27T10:00:00Z, reason: "measured 20 min on the 5.0 instance; the doc's 30 min does not hold" }
```
- `refuted`: a list of refutation events, each with `by` (an actor, §7) and
`at` (an ISO 8601 datetime), plus an optional free-text `reason`.
- A single refuter MAY be written as one bare `{ by, at }` mapping; consumers
MUST treat it as a one-element list, as for `verified` (§5.2).
- `refuted` is independent of `verified`: a concept can carry both, e.g. a
nightly process confirmed it in June and a human refuted it in August.
Both lists are appended to, never overwritten, so history survives.
### Align Trust Tier (§5.3)
A concept is *refuted* when the refutation is newer than the content it refutes:
active refutation ⟺ max(refuted[].at) > generated.at
Verification time does not enter the predicate.
When a refutation is active, the concept's tier is **refuted**, a fourth tier
below *unverified*:
- active `refuted` ⇒ **refuted**
- no `verified` ⇒ *unverified*
- non-`human:` verifiers only ⇒ *machine-confirmed*
- any `human:` verifier ⇒ *human-reviewed*
Of course you could say a concept that is verified by *machine-01* and refuted by
*human-A* might be verified by *human-B*. But I believe being this strict
simplifies managing the concept's verification state, because builds on
the following rules:
1. Re-verifying the same content does not undo a refutation. A later
`verified` entry alone does not lift a refuted concept. Only content that
is newer than the refutation (because it holds a later `generated.at`) can be verified back
into trust. This is what stops a partner's stale copy from talking a
rejected value back into a bundle on merge: the refutation is the newest
event on the record, so it wins.
2. Actor class does not rank refutations. A `process:` refutation is just as
valid as a `human:` one. Refuting is a claim that a check failed, not a
grade. A consumer that wants to weight refuters does so under its own
policy, the way it weights source credibility signals today (§5.1).
Everything else stays as it is: the tier is advisory, not access control,
and a consumer MUST NOT reject a refuted concept (§11). It SHOULD surface the
refutation and SHOULD exclude the concept from in-force retrieval by default,
the way a `deprecated` concept is kept for links and history.
### Open question: should you apply the me logic to verified?
Once `generated.at` advances, should `verified[]` entries older
than the new content still count towards the tier? If they do, freshly
rewritten content inherits verification that applied to its predecessor,
which can not be intended. I would apply the same predicate to both lists
(only events newer than `generated.at` count), but that is a change to
existing §5.3 behaviour and deserves its own decision.
### Composition with #11 (deletion semantics)
`refuted` and #11 sit on different axes and may be composed: `refuted` is a
negative *trust* event on a concept that exists while `removed` / `never_landed`
indicate that concepts don't exist.
### Modelling Decision
- It mirrors a field v0.2 already has. No new enum, no score, no ordering
between producers. `generated`, `verified` and `refuted` together cover the
three acts a trust consumer needs to see: written, confirmed, rejected.
- It keeps §5.1's stance: credibility is still inferred from events with an
actor and a time, not stored as a score.
- It composes with the open proposals instead of overlapping them. `status`
keeps meaning lifecycle, `contested_by` keeps meaning an unresolved edge
between two concepts, and `refuted` is the per-concept verdict neither of
them carries.
## Background
In industrial automation we need a similar distinction to prevent CD systems
from pushing refuted information models (basically hardware manifests) to
live production plants :D I tried to use OKF for a personal project and
noticed you might face similar problems by not tracking failed verifications
in the model. This distinction comes out of Intent Semantics, an
epistemic-status vocabulary for values in industrial information models
(ETFA 2026, DOI: [10.5445/IR/1000195296](https://doi.org/10.5445/IR/1000195296)).
There, "examined and refuted" is a state, which forces a
write before a value may be verified again, so an exchange partner cannot
silently restore it. The resulting epistemic state set might be overkill for
OKF. But I believe adding the third trust record will definitely help.
Ill propose a wording for §5.2/§5.3 if the maintainers want it.
Contributor guide
Research direction
Start by reading OKF v0.2 §5.2 and §5.3, then compare the existing generated and verified trust records with the proposed refuted record and tier rules. Done means the maintainers have resolved the open question about verification timestamps and agreed on precise specification wording and interaction with removed or never-landed concepts.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- yaml
- Domain
- documentation
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100