Skip to content

refactor(evidence): ontology-declared source roles replace named flags - #87

Merged
mroops0111 merged 2 commits into
masterfrom
refactor/ontology-declared-evidence
Aug 5, 2026
Merged

refactor(evidence): ontology-declared source roles replace named flags#87
mroops0111 merged 2 commits into
masterfrom
refactor/ontology-declared-evidence

Conversation

@mroops0111

@mroops0111 mroops0111 commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Summary

Finishes decoupling the source-role taxonomy from the framework. The evidence model stops naming DDD's roles, and role references are now validated against whatever the active ontology declares. Closes the evidence half of #50 and the trust-model design of #68.

What changed

Evidence flags become one role-agnostic field. GraphNodeMetadata.intentMissing / intentConflict / implementationMissing collapse into missingRoles: SourceRole[] (the declared roles whose evidence is missing on this node), and the dead intentConflict flag is dropped. validateEvidence (a framework invariant) now checks presence only: a node needs a sourceReference or a non-empty missingRoles. It never names a role and cannot know the ontology's vocabulary. Its code is renamed to evidence.no-source-or-missing-roles.

Role references are validated at the ontology layer. OntologyTypeValidator already rejects a node/edge type outside the active ontology's declared set. It now applies the same allow-list to a node's missingRoles, emitting ontology.unknown-source-role. The ontology is already loaded into the validation pipeline, so this is not a reverse dependency, it is the same graph-validation the types get.

The last intent/code literal leaves src. The batch-plan v1-to-v2 migration shim (intent/derive to direct/derived) is dropped. Local ~/.braid workspace data was migrated in place, so the framework carries no legacy-format code.

Fixtures. The generic-mechanism tests (source, ontology, ontologies) move to a neutral test vocabulary (alpha / beta), proving the mechanism without naming DDD's roles.

Design stance for #68 (trust / convergence without a ground-truth role)

Confirmation (acceptance 2): core does not hardcode a privileged role. Merge is blind last-write-wins (Model.applyValidatedUpdate), drift is skill-authored and only surfaced by validateEvidence, and SourceRole is an open branded string. No validator ranks one role as authoritative.

The framework stays trust-neutral; trust is an ontology concern. The framework invariant checks structural presence. The ontology layer validates the role vocabulary. What a role means for trust (a ground-truth arbiter versus a non-authoritative claim) is the ontology's and its skills' policy, never the framework's.

Same-role sources conflicting on one node: split by disagreement level, not by role identity. Identity-level disagreement routes to a Clarification (human curation). Field-level disagreement is an ontology policy: an SSoT ontology makes the authoritative role win and records the rest as a DriftIssue, while a no-SSoT ontology records the contradiction as a first-class state and does not force-merge.

Recommended no-SSoT pattern. Model each claim as its own node (per-claim provenance for free), express agreement and disagreement as corroborates / contradicts edges, derive confidence from that topology (skill or view computed), and escalate to a human selectively. This is fully expressible as a plugin today, with no framework change. A confidence number, per-field provenance, and a contradicts edge type are ontology-declared, not framework primitives, because "N agreeing sources equals true" is itself a trust policy the framework must not assume.

#50 litmus outcome (honest note)

grep "'intent'|'code'|source-intent" outside ontology-ddd is not literally zero, and that is expected. Every remaining hit is one of two legitimate kinds:

  • Not a source role. OAuth response_type: 'code' / query('code'), and sourceId / name string literals (proposal-preview, orphanReaper, sourceWebhooks).
  • DDD-preset integration tests. composeFsApp.test, batchRoutes, e2e, historyHooks, historyRoutes, showAll, cli/init. These exercise composeFsApp and the CLI, which intentionally bundle DDD as the coding preset, so DDD roles are the correct data there. Genuinely DDD-specific behavior lives in packages/ontology-ddd/test.

Core and schema are fully role-agnostic, so a third-party ontology declares its own roles and runs the whole loop with no edit to @braidhq/core or @braidhq/schema. The litmus's intent is met.

Verification

  • pnpm typecheck green (15/15), pnpm lint clean.
  • schema 297, core 273 (with two new OntologyTypeValidator role-check tests), server 301, studio 100.
  • The real ~/.braid boots clean against the migrated batch-plan data.

Closes #50
Closes #68

🤖 Generated with Claude Code

mroops0111 and others added 2 commits August 5, 2026 11:03
GraphNodeMetadata's intentMissing/intentConflict/implementationMissing
collapse into one role-agnostic missingRoles[]. validateEvidence checks
presence only, blind to the role vocabulary. OntologyTypeValidator now also
rejects a missingRoles entry the active ontology does not declare, the same
allow-list check it runs for node and edge types.

Neutralize the generic-mechanism fixtures (source, ontology, ontologies
tests) to a test vocabulary. Drop the batch-plan v1 migration shim, the last
intent/code literal in src; local workspace data was migrated in place.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mroops0111
mroops0111 merged commit 2bb6328 into master Aug 5, 2026
7 checks passed
@mroops0111
mroops0111 deleted the refactor/ontology-declared-evidence branch August 5, 2026 08:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant