Skip to content

Proposal: register query-time semantics for supersedes and contested_by on the #16 carrier #22

Open

Description

@andrewcrenshaw

#16 gives relationships a carrier: to, type, direction, and the §5.3 trust shapes one level down. It deliberately leaves type producer-defined and unconstrained, and that is the right call for the carrier. This proposes the other half for two specific types, because a consumer reading type: supersedes still cannot tell whether to drop the target from an in-force query.

Two lifecycle edges, each with its query-time semantics registered beside it. They differ on the axis that drives consumer behaviour: directionality.

Revised 2026-09-14 from review by @ajdelaguila and @3a3; the comment thread carries the derivation.

The two types

supersedes contradicts
Symmetry Asymmetric. The carrying concept replaces the referenced one. Semantically symmetric, stored one-sided. Written on the asserting concept only; the reverse is derived.
Direction Backward in time, to the concept being replaced. Outbound from the asserting concept. direction reads as it does for any asymmetric type.
Query-time Exclude, once affirmed. Drop the superseded concept from in-force retrieval; retain it in the bundle for lineage. Surface both. Never resolve the edge as a verdict, collapse "contested" into "false", or drop a side without human or higher-signal input.
Encodes a verdict? Once affirmed, yes. No. Records that a dispute exists, never who is right.
Inverse emitted? No. Resolution keys on the forward edge only. An inverse spelling gives a producer two ways to state one relationship and a consumer two places to look, which is how a reversed edge survives review (@jpavley shipped one inverted, GoogleCloudPlatform/knowledge-catalog#148). Derived, never written. See the naming section.
Dangling target Not an error. If the target is absent, the carrying concept is current. Not an error.
relationships:
  - to: remember://lesson/lesson-corpus-est-000
    type: supersedes
    generated: { by: remember/0.2, at: 2026-09-12T09:00:00Z }

Targets are stable concept ids per GoogleCloudPlatform/knowledge-catalog#120, not paths, so a file move cannot reattach an edge to the wrong incumbent. @pixie79 reports the same conclusion from the other end on #16: deriving a concept's path from its key guessed wrong for 43 links on a real render, each a valid-looking path to a file that did not exist.

Naming: one stored key, one derived view

  • contradicts is the stored key, on the asserting concept, one side only.
  • contradicted_by is the derived reverse view, computed at read time and never written to frontmatter.
  • contested_by is a deprecated spelling. Consumers SHOULD read it as contradicts.

Under one-sided storage contested_by is inverted: the asserter would carry a key saying it is contested, the reverse of what it asserts. This registration, @inkxel's implementation and Data Olympus's are then one vocabulary rather than three. We ship contested_by today and have the migration to do.

A mirror write, with both records carrying the edge, is a two-write that can half-apply, and a one-sided contest is a different condition from the dangling target ruled benign above. Derivation costs a consumer nothing that it is not already paying: a reverse index over stable ids is what resolves targets at all.

Three rungs, and only the third authorizes exclusion

With verified and generated available on the edge it is tempting to read edge provenance as authorization. It is not, and neither is the middle rung.

  1. Edge provenance - generated / verified on the relationship. Says who asserted the edge. Authorizes nothing. @pixie79 confirms the carrier claims no more: "our edges carry kind, provenance and confidence, and none of that is an affirmation."
  2. Source eligibility - the asserting concept is itself in force. Data Olympus ships this: an in-force query excludes the target of a supersedes edge whose source is in force, an edge asserted from an inbox document excludes nothing whatever status it claims, and a dangling edge excludes nothing because the join needs both ends to resolve.
  3. Attributed resolution - someone affirmed this retirement, recorded as an appended, attributed event.

Exclusion follows affirmation. An automated writer may propose a supersession; the incumbent keeps governing until the resolution event is recorded. Rung 2 is weaker than rung 3 and is named rather than collapsed into it, because it is what a real implementation runs today: source eligibility says the edge comes from something currently governing, it does not say anyone affirmed this particular retirement. That distinction is what a consumer needs when 18,803 of 19,349 edges are derived.

Exclusion requires both. A present forward edge and a readable affirmation, together. An affirmation surviving in log.md after the edge is removed from the successor, or after the successor leaves the bundle, is incomplete evidence, so the incumbent stays in force.

The resolution event

Where it lives: the bundle-root log.md. Nearest-ancestor would make the in-force answer depend on where a concept sits in the tree, so a file move could change which log governs its retirement, contradicting the stable-id rule above. A resolution entry in a non-root log.md is not an affirmation; §9 permits the file at any level, and an entry elsewhere excludes nothing.

§9 supplies the file's shape and no preservation duty (SPEC.md:535-552), so the append-only behaviour this registration depends on is the producer's to supply, not the format's. For a bundle assembled in parts that producer is the merging one: it writes root reserved files after merging and carries forward every log.md entry it did not write, from the existing file or from its own bookkeeping. @3a3's #26 §3.2 now states this (revised 2026-09-14); their merge becomes read-then-add, keeping each such entry unchanged under its original date heading.

Entry shape, in §9's own idiom - its **Update** / **Creation** / **Deprecation** convention, made normative inside this registration rather than in core:

## 2026-09-14
* **Supersession**: `remember://lesson/b` supersedes `remember://lesson/a`. Affirmed by `human:1c8998e4`.
* **Dismissal**: contest between `remember://lesson/c` and `remember://lesson/d` dismissed. Affirmed by `human:1c8998e4`.

A consumer MUST find four things: the disposition word, both stable concept ids, and the attributing actor in §7's form. The date comes from the enclosing §9 heading.

Absent, malformed or undecidable evidence fails safe. If any of the four is missing or unparseable, the entry is not a readable affirmation, so the incumbent stays in force and nothing is excluded. The same answer covers conflicting entries: §9 orders dates newest first and says nothing about order inside a date, so two conflicting entries on one pair under one heading are not decisive. This also answers a real adoption case - @pixie79 reports on #16 that Roteiro populates no author fields and discards a peer's author on import. That producer excludes nothing rather than excluding wrongly, and needs no change to stay conformant.

Where the conformance layer lands: in this registration, not §11. Core should not carry a clause for a community extension it does not define. A consumer implementing this registration gets a checkable bar; a bundle that ignores the registration is unaffected.

Three states, read from the bundle alone

No adjudication engine, no edited records, every resolution an append.

  1. Never questioned - no contradicts pointing at it, not the target of any supersedes. Absence means no dispute asserted, not proven undisputed.
  2. Contested and open - the edge exists, both concepts present, no resolution recorded. Surface both.
  3. Contested and settled - a resolution is recorded, not edited in. The contradicts edge is retained whatever the disposition, so a settled contest stays distinguishable from one never raised. Drop it and a reader returning later cannot tell a question that was settled from one that was never asked.

A supersedes edge with no resolution event yet is a proposal, not a fourth state: both concepts surface and the incumbent stays in force.

Settlement comes two ways.

Supersession - the winner gains the supersedes edge, the loser's validity window closes, both retain contradicts, and exclusion keys on the resolution entry rather than on the closed window. A closed window with no entry is decay, and reading it as affirmation would collapse decay and affirmed supersession into one, which is the silent displacement the invariant forbids.

Dismissal withdraws the contest, not a concept. No window closes, both concepts stay in force, and the entry's whole job is moving the pair from contested-and-open to contested-and-settled. A concept examined and judged wrong is #13's refuted or a supersession; dismissal is not a third way to retire something, and contradicts carries no verdict by design.

Composition

Floor for partial implementation. A consumer that implements the carrier and not this registration excludes nothing. Under exclusion follows affirmation that is the designed failure direction, not an accident.

Provenance

Two production implementations, arrived at independently. Ours ships both keys in the remember exporter with the sample bundle at https://github.com/andrewcrenshaw/remember-okf-sample-bundle. @ajdelaguila's Data Olympus ships source-gated supersession over concept ids and holds contradicts as annotation that never filters, with contest disposition open at knaisoma/data-olympus#241. The two differ on one mechanism: Data Olympus reads a contest-to-supersession count out of git diffs, and we record a resolution event at settlement so the same count is a query. That difference is the argument for rung 3.

The prior text, with the extended composition and a worked sample bundle, was GoogleCloudPlatform/knowledge-catalog#195, now retired in favour of this. Its own adjacent-proposals section predicted this carrier: a broader carrier for producer-defined relations can host these two edges without redefining them, because the query-time semantics attach to the relation and not to the syntax.

Glad to take further convergence edits here and then put it up as a PR.

Activity

  1. ajdelaguila commented on Sep 12, 2026

    @ajdelaguila

    Reviewed. A few things to settle in the text, most of them about rung 3.

    Where the resolution event lives is underspecified for a consumer that has to act on it. §9 fixes the file's shape, a flat list of date-grouped entries newest first under ISO date headings, and then says entries are prose, with the leading bold word a convention rather than a requirement. Nothing in the spec names the fields an affirmation must carry, so two consumers reading the same entry can disagree about whether this particular retirement was affirmed, which is the one question the invariant makes decisive. The fix need not be a separate carrier: register the entry shape inside log.md, name what a consumer must find (both stable ids, the attributing actor, the date), and say what a consumer does when that evidence is absent or malformed. Whether that lands as a conformance layer belonging to the registration or as a companion clause in §11 is your call, but the text should say which, because today a bundle whose resolution entries are unreadable is still conformant with base OKF.

    Related and smaller: §9 allows a log.md at any level of the hierarchy, and the text says "the bundle's log.md" in the singular. Nearest ancestor of the carrying concept and bundle root are both defensible, but left unstated, two conformant consumers can reach different in-force answers from the same bytes.

    On contested_by being symmetric. Requiring both sides to carry the edge is a two-write that can be half-applied, and a one-sided contest is a different condition from the dangling target you already rule benign. Here only the one-sided form is stored, contradicts on the asserting document, with the reverse computed at read time and surfaced as contradicted_by, dangling-safe at both ends. If the registration says one side is sufficient and the inverse is derived, symmetry holds without a write that can half-fail, and the contradicts alias lines up mechanically rather than only sounding similar. The carrier's direction then wants a line saying how to read it on a symmetric type, or that consumers ignore it there.

    Last, worth stating rather than leaving to inference: a consumer that implements the carrier and not the resolution excludes nothing, which under exclusion follows affirmation is the safe direction to fail in. Naming "surface both" as the floor makes that read as designed.

  2. andrewcrenshaw commented on Sep 14, 2026

    @andrewcrenshaw
    Author

    All four accepted, one of them changing a position the text called load-bearing. Revised registration below; the original body stays as filed so the review reads in order.

    1. The resolution entry now has a shape

    You are right that rung 3 was unenforceable. §9 fixes the file and leaves the entry as prose, so "an appended, attributed resolution event" named a location and not a contract.

    Registered entry shape, in §9's own idiom (its **Update** / **Creation** / **Deprecation** convention, made normative inside this registration rather than in core):

    ## 2026-09-14
    * **Supersession**: `remember://lesson/b` supersedes `remember://lesson/a`. Affirmed by `human:1c8998e4`.
    * **Dismissal**: contest between `remember://lesson/c` and `remember://lesson/d` dismissed. Affirmed by `human:1c8998e4`.

    A consumer MUST find four things: the disposition word, both stable concept ids, and the attributing actor in §7's form. The date comes from the enclosing §9 heading.

    Absent or malformed evidence fails safe. If any of the four is missing or unparseable, the entry is not a readable affirmation, so the incumbent stays in force and nothing is excluded. That is the same direction as your point 4 and it answers a real adoption case: @pixie79 reports on #16 that Roteiro populates no author fields and discards a peer's author on import. Under this rule that producer excludes nothing rather than excluding wrongly, and needs no change to stay conformant.

    Where it lands: in this registration, as a conformance layer, not in §11. Core should not have to carry a clause for a community extension that core does not define. Naming it here means a consumer implementing this registration has a checkable bar, and a bundle that ignores the registration is unaffected.

    2. One log.md, at the bundle root

    The bundle-root log.md. Nearest-ancestor makes the in-force answer depend on where a concept happens to sit in the tree, so moving a file could change which log governs its retirement, which contradicts the stable-id rule the rest of this registration rests on.

    The root also matches how a merged bundle is actually built: @3a3 on #26 keeps reserved filenames out of directories more than one part contributes to and has the merging producer write the root index.md and log.md afterwards. Root is the one place a bundle assembled in parts has a single authority.

    3. contested_by becomes one-sided and derived, and this changes our position

    Accepted, and it retires a load-bearing invariant in the filed text.

    Store the edge once, on the asserting concept. The reverse is computed at read time and surfaced as the inverse view; it is never written. Dangling-safe at both ends, and no write that can half-apply.

    What that costs and why we think it is worth paying: the filed text required both records to carry the edge so either reads standalone without a second lookup, a storage-versus-identity split @jpavley contributed on GoogleCloudPlatform/knowledge-catalog#148, with a validator completeness check because a mirror can half-fail. The decider is that a consumer is already building the reverse index. @pixie79 reports on #16 resolving every link through a key -> path map built after placement, after path-from-key guessed wrong for 43 links on a real render. Where that index exists, derivation is nearly free, and jpavley's completeness check stops being an unenforced obligation because there is no longer a second write to lose.

    It also settles the naming honestly. contradicts on the asserting concept with a derived inverse is the same mechanism, not a spelling to alias.

    On direction for a symmetric type: with one-sided storage the question dissolves. direction reads exactly as it does for an asymmetric type, outbound from the asserting concept. The symmetry lives in the query-time semantics, where both sides surface, not in the storage.

    4. Surface-both is the floor, stated

    A consumer that implements the carrier and not this registration excludes nothing. Under exclusion follows affirmation that is the designed failure direction, not an accident of partial implementation, and the text now says so.

    Glad to fold this into the issue body once it has settled, or to leave body and revision separate if that reviews better.

  3. ajdelaguila commented on Sep 14, 2026

    @ajdelaguila

    Leaving the body as filed and folding once it settles works well from here, as long as the fold lands before the PR so a maintainer reviews one document. The root log.md and the conformance-layer placement both read right. One line saying a resolution entry in a non-root log.md is not an affirmation would close the case §9 still permits.

    Three smaller things.

    The dismissal entry does not say which side lost. The filed text has a dismissal close "the dismissed side's window", but contest between c and d dismissed names the pair without a direction, so a consumer cannot tell which window the receipt accounts for. Either the entry names the dismissed id, or dismissal means the contest itself was dismissed and closes no window. Both work, and the text should pick one.

    The log and the frontmatter can disagree, and the fail-safe rule could cover that as well as malformed entries. An affirmed supersession stays in log.md after someone removes the supersedes edge from b, or after b leaves the bundle. Saying exclusion needs both a present forward edge and a readable affirmation keeps the incumbent in force when that evidence is incomplete. The same applies to two conflicting entries on one pair under a single date heading, since §9 orders dates newest first but says nothing about order inside a date.

    On naming, the table still registers contested_by as canonical with contradicts as an alias, while the revision now says contradicts is the same mechanism rather than a spelling to alias. A consumer building the reverse index needs to know which key is stored and whether the derived view has a name of its own. Data Olympus stores contradicts and serves the computed reverse as contradicted_by, never written to frontmatter, which is one answer. The registration only needs to state its own.

  4. andrewcrenshaw commented on Sep 14, 2026

    @andrewcrenshaw
    Author

    All four, and the last one changes a key we ship.

    Folding before any PR, agreed. One document for a maintainer is the right bar and the body will carry the settled text.

    Non-root logs. Added: a resolution entry in a non-root log.md is not an affirmation. §9 permits the file at any level and a consumer may find a resolution-shaped entry there; only the bundle-root log carries affirmations, and an entry elsewhere excludes nothing.

    Dismissal closes no window

    The filed text closes "the dismissed side's window" while the registered entry names a pair without a direction. Taking your second option: dismissal withdraws the contest, not a concept. No window closes, both concepts stay in force, and the entry's whole job is to move the pair from contested-and-open to contested-and-settled so a settled question stays distinguishable from one never raised.

    That composes better than the alternative. A concept examined and judged wrong is #13's refuted or a supersession; dismissal should not be a third way to retire something, and the registration already holds that contested_by carries no verdict by design. The entry needs no direction under that reading.

    Exclusion requires both, and undecidable evidence fails safe

    Accepted, and it generalises the rule rather than adding a case. Exclusion requires a present forward edge and a readable affirmation, together. An affirmation surviving in log.md after the edge is removed from b, or after b leaves the bundle, is incomplete evidence, so the incumbent stays in force.

    Your conflicting-entries case lands in the same rule. §9 orders dates newest first and says nothing about order inside a date, so two conflicting entries on one pair under one heading are not decisive, and the incumbent stays. Undecidable and unreadable get the same answer, which is the point of fail-safe.

    The stored key is contradicts

    Under one-sided storage on the asserting concept, contested_by is inverted: the asserter would carry a key saying it is contested, the reverse of what it asserts. contradicts reads correctly in that position and contradicted_by is its natural derived view. The name follows the storage model, and contested_by was shaped for the mirror-write this registration no longer specifies.

    Registered, replacing the alias row in the body:

    • contradicts is the stored key, on the asserting concept, one side only.
    • contradicted_by is the derived reverse view, computed at read time and never written to frontmatter.
    • contested_by is a deprecated spelling. Consumers SHOULD read it as contradicts.

    That makes @inkxel's, Data Olympus's and this registration's spellings one vocabulary rather than three. We ship contested_by today and have the migration to do, which is the right way round given two of three producers already store contradicts.

  5. 3a3 commented on Sep 14, 2026

    @3a3

    Your revision's §2 holds for the producer it cites: every part contributes to the bundle root and no part owns it, so no part writes the root log.md; the merging producer does, after merging (#26, §3.2, third bullet).

    §2 describes that bullet as filed; it was revised on #26 after your comment there and is now in the #26 body. The half §2 leaves out is the one an affirmation depends on: §9 fixes the file's shape and gives it no preservation duty (SPEC.md:535-552), so the "append-only" the body relies on is the merging producer's to supply. In short, for the fold-in you offered: the merging producer writes root reserved files after merging and carries forward every log.md entry it did not write, from the existing file or its own bookkeeping. Ours, as said on #26, becomes read-then-add and keeps each such entry unchanged under its original date heading.

  6. mlnrt commented on Sep 23, 2026

    @mlnrt

    Just wanted to share how I am planning to handle supersedes in our Arkeology plugin (which uses external storage, AWS S3 Bucket and Vectors, to store artifacts instead of git) and how I plan to map onto the three rungs.

    We agree with "exclusion follows affirmation", and we reach rung 3 without a log.md.
    We have no bundle root, so a resolution entry there is not available to us. Instead we key the in-force decision on the artifact's own retired concept's status: deprecated (§5.4), attributed through that concept's own revised.by.

    Our in-force filter is one clause on the concept being evaluated:

    in-force(A)  =  A.status != deprecated  AND  A.archived == false
    

    archived is our store's own marker (set by an explicit archive operation, orthogonal to §5.4). The supersedes edge does not appear in the clause at all. Taking B —supersedes→ A:

    What exists Is A in force? #22 rung
    B —supersedes→ A. A still stable. yes — the edge is lineage; it excludes nothing 1
    B —supersedes→ A, and B is itself in force (stable, not archived). A still stable. yes — B's own standing says the claim comes from a governing document, not that anyone affirmed this particular retirement 2
    A carries status: deprecated — with or without any edge pointing at it. no 3
    A is archived in our store — whatever its status, whatever edges point at it. no our own lifecycle exit, orthogonal to §5.4; no successor is implied

    Why the flip on A counts as affirmation rather than provenance: the B→A edge is cheap, often machine-derived, and written on a different document than the one it retires — which is exactly why the thread doesn't trust it alone. status: deprecated on A has none of those properties. It is a write to A, so it sits under whatever already governs writes to A. Deprecation is no escalation of power over what any writer to A already holds (they could archive or delete it), and it is attributed. Cross-scope falls out for free: another team's B may declare it supersedes our A; it cannot write our A, so A stays in force in our results and their claim is visible as lineage (In Arkeology we can share artifacts cross projects/teams).

    Two consequences that line up with the registration as revised: a dangling supersedes target is benign (the carrying concept is current), and the edge-without-deprecation state is precisely "proposed, not affirmed" — visible, not acted on.

    One ask. The registration currently names bundle-root log.md as the home of the attributed resolution and says an entry elsewhere excludes nothing. Would you consider naming "the target itself carries status: deprecated, attributed" as a second acceptable form of attributed resolution? It gives store-backed consumers a conformant path, and for bundle consumers it is already what §5.4 means.

    The dependency is that producers write both ends — the edge on the successor and the status flip on the incumbent. Ours does; I'd be interested whether Roteiro's and Data Olympus's do, since if the edge is ever written alone the incumbent stays in force under
    this rule, by design.

  7. ajdelaguila commented on Sep 23, 2026

    @ajdelaguila

    Ours retires the incumbent from the successor's edge alone, which puts us at your rung 2. in_force=true excludes any document that is the target of a supersedes edge whose source is itself in force under the full predicate, meaning status class, validity window, and not a memory-inbox record. A draft, an expired document, one already retired, or an inbox record cannot retire anything by naming it in supersedes. The documentation calls this closing the forgotten status flip gap: A supersedes B, B's own status was never updated, and B still leaves in-force results.

    On your literal question, the two ends are separate writes here. kb_propose_edit names a single target_path, held under a per-path lock, with a compare-and-swap when the caller supplies a base marker, so the edge on the successor and a status flip on the incumbent are two edits rather than one change. A newly introduced supersedes value is checked against a document present in the commit being made. Retrieval exclusion does not depend on a separate status flip on the incumbent, which is the property that matters for your rule.

    The guard on the source and your target-side write are different checks. We test the successor's status, validity window and inbox placement; you tie retirement to the permissions governing the incumbent. Yours gets cross-scope safety out of that, since another team's B cannot write your A, and where a store shares artifacts across teams that is a real advantage of keying the decision on the target.

    Your dangling-edge consequence holds here too, for a mechanical reason: the exclusion query joins edges to documents at both ends. The other one differs, since a qualifying edge is acted on rather than left visible and unacted. What we keep instead is explainability. A plain search still returns the excluded document, and kb_get reports superseded_by as the union of the document's own claim and any reverse edge, so a consumer can see what retired it.

    https://github.com/knaisoma/data-olympus/blob/v0.9.0/docs/serving.md#supersession-graph-exclusion-issue-110-slice-2

    Your ask reads right to me. If the registration names an attributed status: deprecated on the target as a second form of resolution, it is worth saying in the same clause that an edge alone affirms nothing under any named form. Our rule excludes the incumbent before that requirement is met, and naming the floor is what lets a producer writing one end predict the consumers that do not.

  8. DavidROliverBA commented on Sep 27, 2026

    @DavidROliverBA

    Thanks for this thread; it is the most careful discussion of supersedes and contradicts I have seen anywhere, and I wanted to add a second implementation's data point in case it helps the convergence along.

    I maintain AI-XF (https://github.com/DavidROliverBA/ai-xf-format, MIT), a small superset of OKF v0.2 that I use to move knowledge between my own vaults and agents. It has carried typed links, with contradicts and supersedes as core relationship values, since its first draft in July, and I was glad to see this thread settle on the same spelling after dropping contested_by.

    One honest difference, offered as a comparison rather than a counter-proposal. Here, resolution is an attributed event in the bundle-root log.md, exclusion follows affirmation, and malformed evidence fails safe. In AI-XF, resolution is state on the edge itself: state: open | resolved plus a resolved: {by, at, outcome} map. The edge form is a single write with no shared file to fight over; the log form keeps a history and is auditable. I suspect they compose, edge for current state and log for history, and I would happily align AI-XF with whatever this thread lands on.

    What might be useful: before writing the federation rules into AI-XF v0.4, I tested each one. The repo has three deliberately colliding fixture bundles and six re-runnable experiments, plus a run on two real bundles from my vault. The collision experiment found that an unqualified reference across a bundle boundary should never resolve silently (0 silent misresolutions with a warn-and-name rule), and the transport experiment found that a consumer manifest is needed for provenance rather than resolution, which surprised me. The fixtures and results are yours to reuse if they help test a reader against these semantics.

    To be clear about intent: I would much rather OKF win as the standard than have a superset persist. AI-XF exists to try things ahead of the spec, and every feature OKF adopts gets retired from AI-XF in favour of the OKF definition, as happened with the trust fields in v0.2. If this thread's resolution semantics land in OKF, I will do the same here.

  9. andrewcrenshaw commented on Oct 3, 2026

    @andrewcrenshaw
    Author

    Taking @mlnrt's second form, with @ajdelaguila's clause in the same sentence: an edge alone affirms nothing under any named form. Store-backed consumers have no bundle root, so without it rung 3 is out of their reach by construction, and §5.4 already defines deprecated as "no longer current". A write to the incumbent also sits under whatever governs writes to it, which is where the cross-scope safety comes from.

    Two conditions, measured against the four elements a resolution entry carries. The edge stays required: the flip on A supplies the disposition and the pair comes from B's supersedes edge, so a deprecated A with nothing pointing at it is §5.4's business and #22 neither claims nor contradicts it. Attribution needs a source core does not have yet: nothing in the spec attributes a status change and revised.by is #28, so the form is named as attributed and the existing fail-safe applies until a source is readable. The cost is in audit rather than exclusion. A log entry records that B replaced A, the flip records only that A was retired.

    @DavidROliverBA's edge form makes the axis visible: which document the affirmation is written on. The log entry sits in a bundle-root file the producer governs, the flip sits on the incumbent, and resolved: {by, at, outcome} sits on the asserting document. Inside one producer's bundle the three come out equivalent. Across bundles they do not, because edge state lets one bundle retire another bundle's concept with a single write on its own side. Your collision result reaches the same place for identity; applied to authority, a cross-bundle supersession should not affirm itself. So edge state serves well as the current-state view and spares the shared-file contention you name, the same cost behind #26's merge-preservation rule, while deferring across bundles to an affirmation the asserter does not control.

    On whether producers write both ends: ours writes the edge on the survivor and a resolution entry in bundle-root log.md, and nothing on the incumbent. The entry's wording still differs from the registered example, which is ours to bring in line.

    Glad to fold the second form, the clause and the cross-bundle sentence into the body once the wording settles here.

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