Skip to content

Proposal: typed, directed, trust-bearing relationships — today they are prose #16

Open

Description

@pixie79

Second observation from implementing OKF in Roteiro (see also #15, on imported concepts). This one is about the links between concepts rather than the concepts themselves.

Please correct me if v0.2 has a mechanism here I have missed — I could not find one, but this is the kind of thing a spec can express in a place I did not look.

Problem

A relationship in OKF is an untyped, undirected, untrusted markdown link. Everything a producer knows about the relationship has to be flattened into prose.

Roteiro's graph edges each carry four attributes — kind, provenance, confidence, and the import layer they came from. Rendering to OKF, we currently emit:

## Relationships

### calls

* → [checkout](../functions/checkout.md)
* ← [handler](../functions/handler.md) (confidence 0.85)

The relationship type is a markdown heading. The direction is a glyph. Everything else is parenthetical prose. All of it is machine-readable only by a consumer that reverse-engineers our layout conventions — which is precisely the coupling OKF exists to remove, and it is the one part of our bundle that a different producer would encode differently.

Scale, from this repository's own graph: 19,349 relationships across 9 types — calls 10,222, defines 4,652, contains 3,214, imports 967, references 294, and a long tail. An agent asking "what calls this?" has to distinguish a calls edge from a contains edge, and today the only signal is a heading it must parse.

The sharper half: trust stops at the concept boundary

§5.3's tiers describe how much to believe a concept. There is no equivalent for a relationship — so these two render identically:

  • a link a human wrote in an architecture decision record, and
  • a link an embedding-similarity pass guessed at.

In our graph they are different provenance classes (546 authored edges versus 18,803 derived, in this repository). In the bundle they are both a bullet under a heading. A consumer that correctly refuses to trust an unverified concept has no way to apply the same judgement to an unverified relationship — and relationships are what turn a pile of documents into a graph, so they are arguably where a wrong claim propagates furthest.

Proposal

Express relationships in frontmatter, reusing the trust vocabulary the spec already has rather than inventing a parallel one:

relationships:
  - to: ../functions/checkout.md   # REQUIRED. a concept in this bundle
    type: calls                    # REQUIRED. producer-defined, like `type` on a concept
    direction: outbound            # OPTIONAL. outbound (default) | inbound
    verified:                      # OPTIONAL. §5.3 shape, applied to the relationship
      - { by: roteiro/5.0.0, at: 2026-09-01T12:00:00Z }
    generated:                     # OPTIONAL. §5.3 shape
      by: roteiro/5.0.0
      at: 2026-09-01T12:00:00Z

The tier rules of §5.3 then apply unchanged, one level down: a relationship with no verified is unverified, one confirmed by a non-human actor is machine-confirmed, one confirmed by human:<id> is human-reviewed. Nothing new to learn.

type is deliberately producer-defined and unconstrained, exactly as concept type is — the spec's only hard requirement there is that it be non-empty, and the same reasoning applies. Standardising a vocabulary of relationship types across domains would be a much larger undertaking and is not what this asks for.

Not asking for a confidence field. The spec's reasoning against scores — subjective, unportable, goes stale — applies here too, and I agree with it. I mention our (confidence 0.85) only to be transparent that it currently leaks into the body, where it is neither queryable nor governed by anything. Under this proposal we would drop it rather than lobby for it.

Backwards compatibility

  • Optional. A bundle without relationships behaves exactly as today, and body links keep working.
  • Additive to §5.3 rather than a change: the same verified/generated shapes, the same actors (§7), the same tier derivation.
  • Body links are not deprecated. A producer may write both, and a consumer that ignores relationships sees the bundle it sees today. Whether the spec should say anything about keeping the two consistent is worth deciding — my instinct is to say the frontmatter is authoritative where both exist, and say nothing stronger.
  • Composes with Proposal: imported — attribute a concept taken from another bundle without inheriting its trust #15 (an imported relationship reports the upstream's tier without inheriting it) and with Proposal: Third trust field refuted #13 (refuted applies to a relationship by the same rule).

Background

We chose OKF because the trust mapping was, in our ADR's words, "a rename rather than an invention" — our authored/derived/inferred provenance already meant what §5.3's tiers mean. That is a strong endorsement of the concept model, and it is why the relationship gap stands out: the graph we can describe in our own store is strictly richer than the graph we can describe in the bundle, and the part that does not survive is the part that makes it a graph.

Happy to prototype against a draft and report what a real round-trip needs.

Activity

  1. joepietrzak commented on Sep 3, 2026

    @joepietrzak

    @pixie79 I second this, I absolutely think we need directional relationships in OKF v0.3
    I implemented a version of this in telamon
    This will truly enhance data sharing, which is a stated goal of OKF itself. In the physical world, relationships are typed; in a graph database, relationships are typed, there is no reason to not support this explicitly in Spec. One of the biggest changes in 0.2 was provenance which the industry has confirmed is absolutely the right move. I think a no brainer for 0.3 is the addition of this

  2. andrewcrenshaw commented on Sep 11, 2026

    @andrewcrenshaw

    You haven't missed a mechanism - v0.2 has none, and we hit the same wall from a different direction. Our edges are lifecycle and conflict rather than code structure, and we wrote the case up as GoogleCloudPlatform/knowledge-catalog#148 with registration text in GoogleCloudPlatform/knowledge-catalog#195. That work belongs here now, not there, so read this as the proposal moving rather than a second one.

    One thing we'd add to your shape. A type that's producer-defined and unconstrained is machine-readable but not machine-actionable: a consumer reading type: supersedes still doesn't know whether to drop the target from an in-force query. We'd keep your carrier exactly as you've drawn it and register query-time semantics alongside specific types, so the two travel together:

    • supersedes - asymmetric, points backward in time. Query-time: exclude the superseded concept from in-force retrieval, retain it for lineage.
    • contested_by - symmetric. Query-time: surface both and defer adjudication to the consumer. Carries no verdict by design.

    The invariant we'd want in the same clause, because it's what your verified/generated on the edge makes possible: exclusion follows affirmation. An automated writer may propose a supersession; the incumbent keeps governing until an appended, attributed resolution event puts it in force. With 18,803 derived edges against 546 authored, you need that rule more than we do - a similarity pass shouldn't be able to retire a concept by asserting an edge. Your proposal supplies the provenance the rule depends on, which is the part ours was missing.

    Both keys ship in our exporter. @ajdelaguila carries the same two in Data Olympus independently. The two systems differ on one mechanism (GoogleCloudPlatform/knowledge-catalog#195, 5 Sept): Data Olympus holds contradicts as annotation that never filters, so a contest-to-supersession count means reading git diffs, and we append a resolution event at settlement, so the same count is a query.

    Two smaller notes. Targets should key off a stable concept id per GoogleCloudPlatform/knowledge-catalog#120 rather than a path, or a file move silently reattaches an edge to the wrong incumbent. And a dangling target is not an error - if the referenced concept is absent from the bundle, the carrying concept is current.

    Happy to restate the GoogleCloudPlatform/knowledge-catalog#195 registration text against your frontmatter shape and put it up here, or to review yours if you get there first. Either works from our side.

  3. ajdelaguila commented on Sep 12, 2026

    @ajdelaguila

    Data Olympus implements source-gated supersession over concept ids. supersedes and superseded_by are frontmatter ids rather than paths, and an in-force query excludes any document that is the target of a supersedes edge whose source is itself in force. An edge asserted from an inbox document excludes nothing whatever status it claims, and a dangling edge excludes nothing either, because the exclusion join requires both ends to resolve.

    That is a weaker guarantee than the invariant named above, and the difference belongs in the spec rather than in any one implementation. Source eligibility says the edge comes from something currently governing; it does not say anyone affirmed this particular retirement. So if the carrier holds verified and generated, the registration should distinguish provenance metadata on an edge from the attributed resolution that authorizes exclusion, which is the distinction a consumer needs when 18,803 of 19,349 edges are derived.

    On the mechanism named above, contradicts here is annotation that never filters, and recording a contest disposition is open at knaisoma/data-olympus#241. Glad to review the registration text restated against this carrier.

  4. andrewcrenshaw commented on Sep 12, 2026

    @andrewcrenshaw

    Registration text is up as #22, restated against this carrier rather than the flat keys it used before.

    @ajdelaguila your source-eligibility point is the spine of it. The three rungs are separated there and named: edge provenance on the relationship, source eligibility of the asserting concept, and the attributed resolution that authorizes exclusion. Only the third excludes, and rung 2 is written in as the weaker guarantee a shipping implementation actually runs rather than folded into rung 3.

    @pixie79 it registers two types and touches nothing about the carrier. If you would rather the carrier and its first two registered types land together, say so and we will fold it into #16 instead.

  5. pixie79 commented on Sep 13, 2026

    @pixie79
    Author

    Fold or keep separate — keep #22 separate, please.

    The carrier and the registry are different kinds of claim and I think they should be reviewable independently. #16 argues a shape can carry what producers already know; #22 argues what a consumer must do with two specific types. A maintainer could reasonably accept the first and defer the second, and folding them removes that option. #22 also reads well standing on its own, which is the better test.

    @ajdelaguila's three rungs are the right correction and I'd rather not have the carrier claim more than it earns. To be explicit about my side: our edges carry kind, provenance and confidence, and none of that is an affirmation. 18,803 of our 19,349 edges are derived; if edge provenance alone authorised exclusion, a similarity pass could retire a concept here. So rung 1 is all the carrier should be read as supplying.

    Two things I can now offer as measurement rather than opinion.

    Stable ids over paths — agreed, and we have the numbers. We tried deriving a concept's path from its key and it fails quietly: a path depends on the whole placed set (nesting, plus a disambiguating digest when two keys slug alike). On a real render it guessed wrong for 43 links, each a valid-looking path to a file that did not exist. We now resolve every link through a key -> path map built after placement. That is the same reason your "targets key off a stable id" note is right, arrived at from the other end.

    Where I cannot yet help. We do not populate author fields, and our sources entries carry resource only — our writer emits nothing else (crates/rto-render/src/okf.rs:268-273) and our reader currently discards a peer's title and author on import (crates/rto-render/src/okf/read.rs:620-624). So if the registration depends on attributing a resolution to an actor read out of someone else's bundle, our implementation is not yet evidence either way. I would rather say that than imply coverage.

    Happy to review the registration text as it stands in #22.

  6. andrewcrenshaw commented on Sep 14, 2026

    @andrewcrenshaw

    Keeping them separate, agreed, and your reason is better than ours was. A maintainer being able to take the carrier and defer the registry is worth more than the convenience of one thread.

    Your rung-1 cap is the part we would not have been able to state for you. The carrier's own author saying kind, provenance and confidence are not an affirmation settles what #22 can lean on, and 18,803 derived against 546 authored is the number that makes it concrete rather than cautious.

    The 43 links are now in #22. Three of us have arrived at stable ids from different directions - your path-from-key guessing valid-looking paths to files that do not exist, our resolution events surviving a move, and @3a3 on #26 needing paths that re-derive identically across parts. Yours is the only one of the three that comes with a count.

    On the author fields: that limit shaped the revision rather than sitting outside it. #22 now says a resolution entry with a missing or unparseable actor is not a readable affirmation, so the incumbent stays in force and nothing is excluded. Roteiro excludes nothing under that rule and needs no change to stay conformant, which is the right answer for a producer that has not chosen to carry actors rather than a gap it has to close first.

    Review of #22 whenever it suits. @ajdelaguila's has already reshaped it.

  7. mlnrt commented on Sep 17, 2026

    @mlnrt

    I support the idea. My current addition to OKF v0.2 is following:

    relationships:
        - to: /docs/architecture-decisions/adr-2026-05-20-xxxxx.md
          type: builds_on
          direction: outbound
        - to: /plugins/amanox/skills/authoring-skills/references/okf-frontmatter.md
          type: constrained_by
          direction: outbound
        - to: /scripts/validate.py
          type: enforced_by
          direction: inbound
  8. ajdelaguila commented on Sep 17, 2026

    @ajdelaguila

    Data Olympus carries these as frontmatter edges keyed on concept ids rather than paths. supersedes, superseded_by and contradicts each name the target document's id, the linter warns when a value is path-shaped, and for the two supersession keys a target that resolves to nothing is an error that blocks CI rather than an edge that silently retires nothing.

    Worth keying your to: the same way before the shape settles. A path names a location rather than the thing at it, so a rename reattaches or dangles the edge without anything in either file changing. pixie79 put a number on the same root cause earlier here: deriving link paths from keys guessed wrong 43 times in one render, each a valid-looking path to a file that did not exist. Different trigger, same reason, since a path depends on context outside the two files it connects. Your enforced_by edge already points at /scripts/validate.py, so a path-shape check and an unresolved-target check are cheap to add there.

  9. deepdb-ch commented on Sep 21, 2026

    @deepdb-ch

    Writing from the Property Graph Markdown project: the separation emerging here between a relationship carrier (#16) and type-specific query behavior (#22) is exactly the boundary PGM 0.4.0 is designed around.

    PGM 0.4.0 Public Draft 1 is an external semantic profile of OKF 0.2, CommonMark, and YAML. It does not define a relationship vocabulary or give calls, supersedes, or contested_by application semantics. It defines how one exact relationship occurrence, its direction, properties, and optional type are carried without adding Markdown syntax.

    For the example in this issue, the source form is an ordinary concept link:

    [checkout](../functions/checkout.md "{type: calls, generated: {by: roteiro/5.0.0, at: '2026-09-01T12:00:00Z'}, verified: [{by: 'human:alice', at: '2026-09-02T09:00:00Z'}]}")

    PGM interprets this as one directed relationship occurrence from the current concept to ../functions/checkout.md. The complete YAML flow mapping is retained as the relationship property map. A non-empty string type is additionally exposed as the graph-element type, but remains present in the properties. The generated and verified values above are therefore carried without PGM assigning them any trust or exclusion semantics; OKF or a vocabulary profile can define those semantics independently.

    This gives a few compatibility properties that seem relevant to the design choices in this thread:

    • A consumer without PGM support still sees an ordinary OKF/CommonMark link.
    • Every concept-link occurrence already represents one relationship; a title enriches it rather than opting it into the graph.
    • Bare links remain directed but untyped. Unknown types and properties are preserved.
    • Distinct repeated links remain distinct occurrences, including when source, target, and properties are equal.
    • An unresolved target remains a relationship occurrence to a not-yet-present concept ID; it does not require a placeholder node.
    • Direction is always source document → link target. Incoming relationships are a backlink/query view. An authored direction: inbound declaration in the current document would therefore be outside PGM Core.

    The proposed frontmatter relationships: list can still be useful as a normalized projection or index, especially for consumers that do not want to scan Markdown bodies. The important interoperability question is whether it is authoritative source or derived projection. Making both the inline link and the frontmatter entry independently authoritative creates a synchronization problem and makes exact link occurrences ambiguous. PGM deliberately keeps the metadata attached to the link occurrence that asserts the relationship.

    PGM does not solve the separate stable-concept-ID question raised above. It follows the pinned OKF 0.2 concept/path model; its portable relationship keys and occurrence IDs are deterministic and bundle-relative, but change when a source ID, target ID, or property map changes. A future OKF stable-ID mechanism can be composed with the carrier without changing its occurrence semantics.

    The public draft includes a reference processor, executable conformance tests, deterministic JSON/Cypher projections, and a 46-concept/124-relationship fixture. An opt-in NornicDB adapter is also being implemented in orneryd/NornicDB#390.

    If useful, the PGM project can contribute a compact interoperability fixture for this issue: the same Roteiro-style relationships represented as PGM source, expected Core/JSON output, and a deterministic projection to the proposed relationships: list. That would let the carrier and the frontmatter index be compared before either is made normative.

  10. andrewcrenshaw commented on Sep 21, 2026

    @andrewcrenshaw

    contested_by is the deprecated spelling as of last week. #22 (query-time semantics for supersedes and contradicts) registers contradicts as the stored key, contradicted_by as the derived view that is never written to frontmatter, and contested_by as deprecated. We ship contested_by today and have the migration to do, so the example still matches a real bundle, ours.

    One record authoritative, the other derived. Whether the frontmatter list is source or projection is the same trade we ruled on #22 for the other axis: a mirror write, with both records carrying the edge, is a two-write that can half-apply. We store one direction and derive the reverse at read time, and @jpavley's production evidence on inverted edges is what settled it. The same test on inline-versus-frontmatter puts the assertion on the link occurrence and makes the frontmatter list an index over it. Two independently authoritative records of one relationship is a synchronization problem whichever axis it runs on.

    Separately, and not about this thread: your normative OKF baseline pins okf/SPEC.md in knowledge-catalog, which is the frozen snapshot and predates #6's explicit-offset requirement. #24 is the live thread on what okf_version: "0.2" now names, with two implementations there reading it opposite ways.

    The interoperability fixture would be useful, and the projection is the part we would reach for: the same relationships as PGM source, as a #16 relationships: entry, and the deterministic mapping between them. #22 acts at query time on whatever the carrier delivers, so a carrier with a defined projection is one we can evaluate against rather than guess at. We're glad to supply the supersedes and contradicts side of it from our bundle if that helps.

  11. deepdb-ch commented on Sep 22, 2026

    @deepdb-ch

    Thanks — three useful points of convergence, and one correction on my side.

    First, I should have written contradicts, not contested_by. In the fixture, contradicts should be the stored predicate, contradicted_by a derived view that is never serialized, and contested_by at most a deprecated-input case.

    Second, agreed on authority: a PGM link occurrence is the assertion; a relationships: entry should be a deterministic projection of that occurrence, never a second independently authoritative record. That gives us a testable mapping without introducing a two-write synchronization problem.

    Third, the PGM baseline pin is intentional. PGM 0.4.0 Public Draft 1 normatively identifies the exact OKF commit 3fcbb9f… and its SHA-256, so this release does not silently absorb later changes from a moving main. You are right that the pinned text predates #6’s explicit-offset requirement. I therefore read #24 as input to a future, explicitly versioned PGM baseline revision—not as something that should retroactively change 0.4.0. We can make that boundary more visible in the fixture documentation.

    I would welcome the supersedes and contradicts cases from your bundle. A compact fixture could contain the same assertions in four views: PGM Markdown source, expected PGM reference JSON, deterministic #16 relationships: projection, and the derived query view. It should also cover an untyped link, repeated equal occurrences, an unresolved target, and verify that contradicted_by is derived rather than stored.

    If that scope works for you, the PGM project can prepare the carrier and projection sides while you supply the two vocabulary-specific cases.

  12. mlnrt commented on Sep 22, 2026

    @mlnrt

    @deepdb-ch @andrewcrenshaw the prose vs frontmatter authoritative record and the risk of drift is an issue. In our Agentic spec driven development framework, I basically took the total opposite direction than you @deepdb-ch with PGM. Reference links inside the artifact are prose (e.g. "specification document xyz states that...") without the link. The relationships/links are all in the frontmatter.

    Going forward, I am curious if at this point OKS maintainers are considering this relationships key proposal for future version or not at all?

  13. andrewcrenshaw commented on Sep 22, 2026

    @andrewcrenshaw

    That scope works. We can supply both cases from the published bundle at 3806111, which is the commit @leesharks000 ran the cross-implementation test against, so the inputs come with a third-party reproduction behind them.

    What the bundle emits today, keyed on stable ids rather than paths:

    supersedes: okf-conformance-predecessor-000
    contested_by:
      - okf-conformance-disputer-002

    Two things follow from that. contested_by is the exporter's current output, so the concept is an actual instance of the deprecated-input case rather than a hand-written stand-in for one, and contradicts arrives with the exporter migration. Neither target resolves to a concept in the bundle either, so the same file carries your unresolved-target case as real producer output: under #22 the carrying concept stays in force and nothing is excluded.

    The fourth edge case is the one worth keeping prominent. Whether contradicted_by is derived rather than stored is what decides if a consumer can round-trip the registration at all, and a fixture is where that stops being a claim in prose.

    On the pin: the exact commit, its SHA-256, and the MUST against substituting a moving branch already close the drift question, and #24 is an argument about what a version string names rather than what a hash names. An explicitly versioned baseline revision is the right place for the offset change to land.

    One for @pixie79 rather than for us. If a relationships: entry is a deterministic projection of the link occurrence, that is a different authority model from the carrier as drafted, where a producer writes the list directly and Roteiro emits it from its own graph. Worth settling with him before the projection side goes into the fixture.

  14. andrewcrenshaw commented on Sep 22, 2026

    @andrewcrenshaw

    Three routes to the same requirement, and they agree more than the framing suggests. PGM puts the assertion on the link occurrence and derives the frontmatter list. Your framework keeps links out of prose, so there is no second record to drift against. #16 as drafted has the producer write the list directly. All three end at one authoritative record per relationship and differ on where it lives, and none of them allow two independently authoritative copies of one edge. That constraint is the part worth carrying into whatever the carrier becomes.

    On the maintainer question, the observable state rather than a reading of it. The last commit here is ad30107 on 21 August, the merge of #6. Five community PRs are open from early September (#17, #18, #21, #23, #25) with no review on any of them, and the only comments on them come from the CLA bot. #19 was closed by its own author rather than by a maintainer. No maintainer has commented on a community proposal in this repo, and the nearest precedent, GoogleCloudPlatform/knowledge-catalog#303, has been open since 17 August.

    That is the state and not a forecast. What it argues for is converging in the open first, so that whatever does get reviewed arrives with one shape behind it rather than four. The past week has mostly gone that way: #30 folded into relationships:, PGM defines a projection onto the carrier rather than a rival to it, and #22 sits above it on two predicates.

  15. deepdb-ch commented on Sep 22, 2026

    @deepdb-ch

    That contrast is precisely why PGM deliberately does not introduce a frontmatter relationship list.

    A relationships: block uses YAML, but OKF would still need to define an additional relationship-record schema: fields such as to, type, direction and provenance, plus identity, occurrence and synchronization rules. Where the prose already contains the link, the relationship must then either be maintained a second time in frontmatter or one representation must be declared derived.

    PGM instead reuses two existing syntaxes without adding a new Markdown construct or a relationship-specific property language:

    • The existing CommonMark link occurrence is the relationship assertion.
    • Its optional title is interpreted as a complete YAML flow mapping.
    • An existing link can therefore be enriched semantically in place.
    • The properties remain attached to the exact link occurrence and its human-readable context.
    • YAML already supplies the property syntax, including nested values.
    • Ordinary Markdown and OKF consumers still see the original link.
    • A PGM-aware consumer additionally obtains the complete property map and optional type.

    This makes the PGM representation deliberately sparse: one relationship occurrence, one location and one authoritative record. A frontmatter relationships: list can still be generated as an index or projection, but it need not become a second authored representation.

    Your frontmatter-only design is internally consistent because the prose intentionally contains no links, so it avoids duplication by choosing a different source of truth. The trade-off is that the semantic assertion no longer resides where the human-readable reference occurs. PGM chose inline, in-place enrichment because it preserves that locality, requires less additional specification, and degrades gracefully to ordinary Markdown.

    That is the architectural distinction the interoperability fixture should make explicit: PGM relationships are asserted at link occurrences; a frontmatter list, when present, is a derived projection rather than the semantic source.

  16. andrewcrenshaw commented on Sep 22, 2026

    @andrewcrenshaw

    One constraint on the inputs we offered, since it decides how those two cases sit in that frame. The bundle at 3806111 carries no prose links for them at all. supersedes and contested_by are frontmatter keys on concept ids, written by the exporter, with no link occurrence anywhere to project them from. Same shape as @mlnrt's, reached from the generation side rather than the authoring side.

    So for the two vocabulary cases the four views do not stack into one chain. There is no PGM source to derive them from unless one is written for the fixture, and a synthesized source would turn those rows into a demonstration rather than production output, which is the thing they are there to supply.

    Naming the producer's authoring mode per case would hold both without either taking the other's ground: PGM-native assertions projecting to a relationships: index, and frontmatter-native output where the frontmatter is the record. Both ship today, and a consumer meeting an OKF bundle in the wild will meet both.

  17. mlnrt commented on Sep 22, 2026

    @mlnrt

    @pixie79, @deepdb-ch, @andrewcrenshaw in the relationship proposal, if directions is outbound only like PGM: How do you plan to deal with for example with the case of one of the relationship being pointed at being deleted? Because we now have a broken link that can't be cleaned up when that artifact is deleted since we do not know what is referencing it and searching the entire corpus for artifacts referencing the one we are about to delete does not scale.

  18. deepdb-ch commented on Sep 23, 2026

    @deepdb-ch

    @mlnrt Good question. In PGM, outbound describes where an assertion is authored, not how incoming references are queried. A consumer can maintain a derived reverse index from target concept ID to source document and link occurrence. When a source changes, it updates that document’s index entries. Before deleting a target, it queries the index and visits only the sources that actually reference it. Building the index initially requires a corpus scan; each deletion does not.

    PGM does not prescribe the deletion policy. An application can block deletion while references exist, retain unresolved relationships, or update the referring documents as an explicit migration. PGM Core does not silently remove source links when their target disappears. An outbound-only frontmatter list needs the same reverse lookup; placing the assertion in frontmatter does not by itself provide an inbound index.

  19. deepdb-ch commented on Sep 23, 2026

    @deepdb-ch

    @pixie79 Your handler example makes the property-carrier question concrete. PGM 0.4.0 can move the prose annotation onto the existing link occurrence:

    - ← [handler](../functions/handler.md "{confidence: 0.85}")

    A PGM-aware consumer reads the YAML flow map in the Markdown link title as properties of that specific relationship. The same map can carry an optional type, provenance, import layer, or nested values—without a separate frontmatter relationship record. That is the property-graph characteristic: the relationship itself carries properties, rather than being only an unannotated triple.

    This does not ask OKF to standardize confidence scores. PGM neither requires confidence nor assigns it trust semantics; Roteiro can omit it if scores are not portable.

    One direction caveat: ← remains prose, not a PGM direction operator. In PGM Core, the link above asserts this document → handler. If the intended assertion is handler → this document, the authoritative link belongs in handler.md; this line can remain a derived backlink display.

  20. andrewcrenshaw commented on Sep 23, 2026

    @andrewcrenshaw

    The premise worth testing first is whether a stale edge needs cleaning up at all. #22 rules that it does not: if the target is absent the carrying concept is current, and a dangling edge excludes nothing, because the join needs both ends to resolve. Under that rule a deletion leaves no repair owed on any referrer, and the corpus scan you are pricing drops off the critical path.

    What the deleted end owes instead is a record at the target's own id, in the machine index rather than in prose. Ours is published, and @leesharks000 confirmed it consumer-side against the artifact before we shipped it (#11):

    "remember://lesson/okf-conformance-tombstoned-000": {
      "id": "remember://lesson/okf-conformance-tombstoned-000",
      "presence": "removed",
      "date": "2026-07-20T00:00:00.000Z",
      "reason": "curation",
      "recorded_by": "curator-conformance",
      "successor": "remember://lesson/okf-conformance-fixture-001"
    }

    A consumer resolving a target that is no longer there reads one entry keyed by the id it already holds, and learns whether the concept was removed or never landed, and for a removal where it went. That is a lookup at the target rather than a search for referrers, and it separates a deletion from a typo, which a broken link cannot do on its own.

    @deepdb-ch's reverse index is what you need to notify or migrate referrers, and that is a policy choice rather than a correctness requirement. The two compose: the absence record makes a stale edge safe to leave, the index makes it findable when you want to move it.

    Neither the carrier nor the direction field answers deletion, and your question is what puts that in the open. Glad to put the absence-record shape alongside the two vocabulary cases in the interoperability fixture if it earns its place there.

  21. leesharks000 commented on Sep 23, 2026

    @leesharks000

    an ontology that deletes its own deletions is running blind

  22. deepdb-ch commented on Oct 2, 2026

    @deepdb-ch

    @pixie79, your Roteiro example shows why a relationship needs its own trust signal. Suppose Roteiro infers that checkout calls handler. In checkout.md, PGM records the claim on the link itself:

    [handler](../functions/handler.md "{type: calls, generated: {by: roteiro/5.0.0, at: '2026-09-01T12:00:00Z'}}")

    This records who produced the relationship, not that anyone checked it. With no verified event, the relationship is unverified—even if the checkout concept itself is human-reviewed.

    If an automated check confirms the call, the link is updated and becomes machine-confirmed:

    [handler](../functions/handler.md "{type: calls, generated: {by: roteiro/5.0.0, at: '2026-09-01T12:00:00Z'}, verified: {by: 'process:ci', at: '2026-09-02T08:00:00Z'}}")

    If Alice subsequently verifies it, both checks remain recorded. Because one verifier is human, the relationship becomes human-reviewed:

    [handler](../functions/handler.md "{type: calls, generated: {by: roteiro/5.0.0, at: '2026-09-01T12:00:00Z'}, verified: [{by: 'process:ci', at: '2026-09-02T08:00:00Z'}, {by: 'human:alice', at: '2026-09-02T09:00:00Z'}]}")

    These are successive revisions of one authored link, not three relationship records to keep in sync. The verification stays with the assertion it concerns.

    PGM Core preserves these YAML properties without assigning a trust tier. The optional PGM OKF Relationship Trust Profile v1 applies OKF's three-tier derivation to each relationship occurrence. A PGM consumer may preserve verified without deriving a tier; a processor claiming the profile derives the advisory tier from it. The executable example tests all three tiers.

    Would this preserve the distinction you need between a relationship Roteiro inferred and one that has actually been checked?

  23. DavidROliverBA commented on Oct 2, 2026

    @DavidROliverBA

    One measured consequence of the dialects coexisting, for whoever weighs the carrier.

    We ran two shipping OKF extensions against each other (E9). KnowledgeX writes supersedes: and contradicts: as top-level lists of file names; AI-XF writes links: [{rel, to: <id>}]. Both bundles are valid OKF, and each tool checks the other's without errors. But each tool's maintenance checks then report the other's retired concepts as "deprecated without a successor", and AI-XF counted a KnowledgeX contradiction as zero open contradictions. Nothing fails, so nothing tells you.

    That is an argument for a carrier landing before the dialects multiply further, and for keying to on ids, as @ajdelaguila suggests: KnowledgeX's own docs note that an editor rename updates body links but not the path-valued supersedes keys.

  24. deepdb-ch commented on Oct 3, 2026

    @deepdb-ch

    @mlnrt @andrewcrenshaw think we should follow the same principle as OKF here: the relationship semantics themselves should not require referential integrity. OKF explicitly allows links to missing concepts, and PGM relationships likewise remain syntactically valid even if their target cannot currently be resolved.

    Referential integrity is then a concern of the consuming application rather than of the relationship representation itself. Applications that need stronger guarantees can implement them using tombstones/absence records, reverse indexes, deletion policies (restrict/cascade/delete), or similar mechanisms.

    This keeps the core semantics simple and interoperable.

  25. deepdb-ch commented on Oct 11, 2026

    @deepdb-ch

    @andrewcrenshaw Thank you for the bundle and for clarifying that its supersedes/contested_by assertions have no prose links. The executable PGM ↔ #16 interoperability fixture is now published, with tests and expected outputs.

    For the link-native case, it provides the Markdown source, exact PGM reference JSON, a deterministic projection into the proposed relationships: list, and a trace from each PGM occurrence ID to its list index. Its four projected entries match the independently authored frontmatter example on the #16 fields. Repeated identical links remain separate occurrences. The projection explicitly reports confidence as omitted, since the draft list has no field for it; it does not claim a lossless conversion.

    Your commit-pinned remember concept and root log are included verbatim and separately from our clearly labeled synthetic PGM supersedes/contradicts example. Because your original is frontmatter-native and contains no PGM link assertions, its PGM-link projection is correctly empty. The informative #22 query preview reads its contested_by as the deprecated input spelling of contradicts; contradicted_by appears only as a derived reverse view in the resolved synthetic case, never as a stored assertion. The two targets in your pinned concept do not resolve, so that input produces no exclusion or reverse view. This previews the open #22 proposal; it is not an adopted OKF rule.

    One concrete gap remains: this #16-shaped projection emits a relative Markdown path in to, whereas the #22 use case needs a stable concept ID. The synthetic query example uses an explicit path-to-ID lookup, but we do not yet claim a portable resolver or full #22 interoperability.

    Would you check whether the two authoring modes and their expected outputs reflect the carrier boundary you had in mind—especially duplicate occurrences and stable-ID resolution? The README lists the exact commands and limitations.

  26. mlnrt commented on Oct 13, 2026

    @mlnrt

    Cross-linking #32, since it proposes something the relationships list here would need as well.

    #32 is about lists read across a trust boundary: a concept one team publishes, read by another team's agents, whose references include material that reader is not allowed to see. Silently dropping those entries makes the list look complete when it isn't, which misleads any trust judgement made from it. #32 proposes one marker per list, as its last entry:

    relationships:
      - to: adr-2026-05-20-agents-md-monorepo
        type: builds_on
      - withheld: 2      # or `withheld: true` when the count itself is sensitive

    The party serving a partial view MUST emit the marker whenever it removes an entry, and a consumer SHOULD show it. The marker carries no other key, so it has no to and no type.

    #32 was written for sources, but the same problem applies here: a builds_on or supersedes edge whose target is internal, where the target id can itself be sensitive (incident-2026-09-01--…).

  27. andrewcrenshaw commented on Oct 13, 2026

    @andrewcrenshaw

    The authoring-mode boundary is the one we meant. The frontmatter-native source stays verbatim and separate, its PGM-link projection is empty rather than synthesized, and the pinned files match our SHA256SUMS at 3806111.

    That pin predates three exporter changes, and the bundle's current commit gives the fixture two cases 3806111 cannot. At 500ff25d6f79ea0160771b3f4cda5762dee08ed6 the concept stores contradicts with no contested_by, and bundle-root log.md carries an attributed resolution in the shape #22 registers:

    * **Supersession**: `remember://lesson/okf-conformance-fixture-001` supersedes `remember://lesson/okf-conformance-predecessor-000`. Affirmed by `human:1c8998e4`.

    The concept file hashes to 124116df0e3745101bf0c630366fd58d73ac4b107ff1a66e86b2f5d0b55acc0c and log.md to a1f0a09c00e3c8f8cba7677925ae7a7318051c6128b3f4acb7e599f235e88883. Keeping 3806111 as the deprecated-input case and adding 500ff25 as current key plus affirmation would cover both. The predecessor is still absent, so the affirmed case still excludes nothing: it shows a readable affirmation with nothing to remove.

    Two things in query_view.py the newer pin would exercise. It reads contested_by by name, so it would need contradicts as the stored field with contested_by as deprecated input. And _root_log_has_resolution matches any Supersession entry, where #22 keys on the pair: an entry counts for this edge only if it names this source, this target and an actor. The entry above parses with a reader built from the #22 example alone.

    Duplicates. Separate occurrences in the projection are right. #22 decides on the pair, so several identical supersedes occurrences carry evidence and still produce one in-force answer.

    Stable ids. stable_id_by_path is the resolver #22 assumes, where "a reverse index over stable ids is what resolves targets at all". Within one bundle that is portable: a path maps to the target document's stable id, a target with no stable id stays unresolved and excludes nothing, and on #30 we proposed treating an id that resolves to two concepts the same way. Across bundles it needs a bundle identity, which none of the proposals defines yet.

  28. deepdb-ch commented on Oct 16, 2026

    @deepdb-ch

    @andrewcrenshaw Thank you for the precise review. I’ve published the corrected interoperability fixture and regression tests.

    The 3806111 Remember extract remains a separate, byte-verified deprecated-contested_by input. The new 500ff25 extract is also kept verbatim and separately: it stores contradicts and includes your attributed bundle-root Supersession entry. Both frontmatter-native sources still have no PGM link occurrences to project.

    The informative query preview now applies Remember’s explicitly documented remember://lesson/<id> form before joining its bare frontmatter IDs to the log. A supersession entry counts for an edge only with a valid date heading, the exact ordered source–target stable-ID pair, and a readable actor—not merely because some resolution marker appears in the bundle. The 500ff25 affirmation is therefore recognized for its pair; the predecessor is absent, so nothing is excluded. Tests also reject unrelated, reversed, malformed, and non-root entries for that pair.

    For duplicates, the PGM carrier and candidate relationships: projection retain each link occurrence. A regression test creates two equal supersedes occurrences and checks that the query preview makes one decision for their resolved stable-ID pair and type, with both occurrence IDs retained as evidence. Missing or duplicate stable IDs remain unresolved and cannot cause exclusion.

    This is still a narrow preview of the open #16/#22 proposals, not a claim of OKF conformance: source eligibility, conflicting dispositions, and cross-bundle identity remain outside the fixture. Does this now capture the occurrence-versus-pair boundary you intended?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions