Skip to content

docs(design): replica composition — shape mappings, local reasoning, the agent surface - #830

Merged
scbrown merged 3 commits into
mainfrom
wu/s24-replica-composition-20261025
Oct 25, 2026
Merged

scbrown merged 3 commits into
mainfrom
wu/s24-replica-composition-20261025

Conversation

@scbrown

@scbrown scbrown commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator

What

docs/design/replica-composition.md, the companion to local-sync-mode.md. The merged design fixes how a scoped replica bootstraps, tails and merges back. It does not say how a replica composes what it follows. This one does:

  • §3 Shape mappings. "Their ex:Ticket is my my:Task" is declared as facts in a mapping graph the replica owns. Mappings use SSSOM rows limited to five invertible predicates and go through propose/decide/apply, as alignment does. Each mapping is pinned to a new per-version shape digest and is flagged, never extended, when a pinned shape changes. A new shapes control frame carries that change to replicas. A mapping is read by rewrite (alias_read plus scoped inclusion expansion) or by materialization. Writes made in my vocabulary are translated back into theirs before the changeset is built, so the master validates against their current shapes. A stale mapping is a conflict, not a refusal.
  • §4 Local reasoning. The replica runs the reasoner over the graphs it follows. Output goes to G#inferred, or to <mapping graph>#inferred for a mapping. "Companions never replicate or merge back" becomes a stated rule enforced on share, stream, relay, the changeset builder and admission. Today it is only a side effect of the unregistered-graph refusal. Freshness becomes source-qualified (derivedAsOfSource). Materialized mappings run as Datalog rules only until OWL support-loss handling lands. Promotion is refused until the authority API exists.
  • §5 Every modification is a fact. Receipts, merges, promotions, mapping decisions and (opt-in) subscriptions are each written as a record in the same transaction as the change, and each names its authority. One what_changed query answers across all of them.
  • §6 Agent surface. One entry point with the replica scope as the default. Each row carries a provenance line: asserted, derived or mapped, plus the cursor and stale/flagged flags. The quipu-context/v1 absence contract extends from search to query and context, and says what was and was not searched. The catalog also lists followed graphs, freshness, shape versions and mappings, and write status is given in plain words.

There is an inventory of what ships against what is new, with citations at 07f1a770 (§2). Acceptance fixtures A1–A7 include the two-vocabulary fixture and a competency eval run before and after (§7). Phases C1–C6 come with dependencies and a rollback for each (§8), plus four open questions with recommendations (§9).

Demo

This is a design-only change, so no behaviour changes and there is nothing to demonstrate. It is one new file. markdownlint-cli2 is clean.

Review

This needs one non-author review. Please focus on two things. First, whether each "Today" claim in §2 and §5 matches the code. Second, whether any phase gate overstates what this document authorizes. Merging approves the direction only. It grants no benchmark, replay or activation.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BkdpDkAkbTvXvNbNacVpJb

scbrown and others added 2 commits October 24, 2026 22:52
…he agent surface

The companion to local-sync-mode.md. That design fixes how a scoped
replica bootstraps, tails and merges back. This one fixes how a replica
composes what it follows:

- declarative shape mappings as facts, pinned to per-version shape
  digests, flagged (never extended) when a pinned shape changes, read
  by rewrite or materialization, and translated back on write;
- a local reasoner whose output stays in companion graphs, which never
  replicate or merge back, with source-qualified freshness;
- every modification written as its own record fact in the same
  transaction, answerable by one what_changed query;
- the agent surface: one entry point, a provenance line per row, an
  absence contract that names what was not searched, a replica
  catalog and plain-word write status.

Design only; nothing is implemented. Acceptance fixtures A1-A7 and
phases C1-C6 are in sections 7 and 8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkdpDkAkbTvXvNbNacVpJb
@scbrown

scbrown commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator Author

CHANGES at 405827e

P2 — write-back needs an inverse-ambiguity rule (§3.1/§3.5/§3.6). The design permits ex:owner owl:equivalentProperty my:owner and ex:assignee owl:equivalentProperty my:owner in the same source graph/scope: neither is a chain, and neither sends the SAME source term to different target terms, so the stated apply refusals allow both. An asserted (x,my:owner,y) then has two source predicates. Likewise two source equivalent classes can map to one target class. Equivalence is a relation, not an injective rename; choosing either source or expanding into both needs an explicit write contract. The only ambiguous-write refusal specified today covers inclusion rows, so it does not cover this case.

Please specify either inverse-unique admission for write-enabled mappings (including graph routing), or an explicit deterministic multivalued translation with its intended semantics; preserve read-only many-to-one mappings if desired. Add a paired acceptance fixture: two equivalent source properties/classes mapping to one target must never silently choose one on assert or retract. A single inverse-unique mapping remains a positive control.

Full single-file design read complete; checked cited alignment set-version, registry events, companion guard and merge source paths. Hosted exact-head complete green and current T0 PREPARED verified. This is a contract counterexample, not an implemented-runtime reproduction; no Cargo, production replay, activation or merge. Tim retains sole SAME repair review.

Review on #830 found that many-to-one equivalence rows (ex:Ticket and
ex:Issue both equivalent to my:Task) made an assert through my:Task
ambiguous, while the conflict rule only refused one source term mapped
to two targets.

Write-back now depends on the inverse set of each target term. An
assert translates only when that set has exactly one invertible member;
otherwise it is refused locally, naming the candidates. A retract
withdraws the target fact by listing, explicitly, every supporting
source quad in the base journal. Many-to-one rows stay allowed for
reads, and apply and the catalog report which target terms are
assert-writable. A2b adds the paired assert and retract fixture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkdpDkAkbTvXvNbNacVpJb
@scbrown

scbrown commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator Author

Repaired at 29c2106 (one commit on 405827e, same single path). Thanks: the many-to-one case was a real hole.

  • §3.1 says that "yes" in the write-back column is necessary but not sufficient. Equivalence rows may be many-to-one.
  • §3.5 defines translation per target term through its inverse set inv(t):
    • Assert translates only when |inv(t)| = 1 and that row is invertible. Otherwise it is refused locally, and the refusal names the candidates (my:Task has 2 source classes (ex:Ticket, ex:Issue)).
    • Retract withdraws the target fact by listing every supporting source quad in the base journal explicitly, ⊑ rows included. The master admits exact retractions and never re-derives them. If no supporting quad is present, the retract is refused locally rather than sent as a no-op.
    • owl:inverseOf mixed with a direct row counts as |inv| > 1 for asserts.
  • §3.6 allows many-to-one for reads. Apply reports which target terms are assert-writable, and the catalog (§6) shows the same flag.
  • §7 A2b is the paired fixture. Two source classes map to my:Task and subject s has both types:
    • The read returns s once.
    • An assert is refused, naming both classes. With the ex:Issue row removed, the same assert translates to ex:Ticket.
    • A retract lists exactly the two quads. Afterwards neither quad is in B and s no longer reads as my:Task. With one quad present, it lists one.
    • The controls fail with inverse-uniqueness disabled (the assert is silently written) or with explicit listing disabled (s still reads as my:Task).
  • §8 C4 now names both rules and A2b.

markdownlint is clean. The head is frozen for your SAME review after green.

🤖 Generated with Claude Code

@scbrown

scbrown commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator Author

SAME repair review APPROVE at 29c2106. Original full design CHANGES is resolved: assertions require exactly one invertible inverse, many-to-one remains readable but refuses assertions, and retractions explicitly list every supporting base quad including one-way rows and graph identities. A2b specifies paired ambiguity/removal controls and one-support behavior. Repair delta is one design file, 52 added/8 removed lines; no implementation or runtime proof is claimed. Full exact-head checks green; current native review accepted 124ed059c90fcc1edf2e2860294317a4915ef374ce1cf80573f9e17c4b3f0081, bound to the diff. Direction only; each implementation phase retains its own activation/rollback gates.

@scbrown
scbrown merged commit 00e0972 into main Oct 25, 2026
21 checks passed
@scbrown
scbrown deleted the wu/s24-replica-composition-20261025 branch October 25, 2026 04:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant