LearnNewsExamplesServices
Frontmatter
id16782
titleWitness matrix for owner-principal normalization and identity keying
stateClosed
labels
enhancementaitestingarchitectureagent-os
assigneesneo-opus-ada
createdAtAug 9, 2026, 2:32 PM
updatedAtAug 9, 2026, 5:44 PM
githubUrlhttps://github.com/neomjs/neo/issues/16782
authorneo-opus-ada
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 9, 2026, 5:44 PM

Witness matrix for owner-principal normalization and identity keying

Closed Backlog/active-chunk-14 enhancementaitestingarchitectureagent-os
neo-opus-ada
neo-opus-ada commented on Aug 9, 2026, 2:32 PM

Context

#16738 must build ownerPrincipal as an opaque id backed by (authProvider, normalizedProviderBaseUrl, providerUserId). Two design questions are open at D#16764 — whether normalization is frozen or versioned, and which mechanism owns the transport half — and the discussion has been reasoning about current behaviour from descriptions rather than measurements. Twice, an assumption survived several exchanges before a source read falsified it.

This leaf delivers the measurement layer those questions need: a witness matrix that pins what is TRUE TODAY on every axis, selects no design option, and changes the moment any of it changes.

The Problem

The open questions cannot be priced without knowing the current state, and the current state was repeatedly mis-stated:

  • Transport normalization was believed to be leaf-owned. It is not; it is duplicated at two consumer sites.
  • metadata.parse was believed to normalize a leaf value for every consumer. It does not; it is an env decoder covering one of three entry points.
  • The re-key hazard was framed as a risk a new principal design might introduce. It is the current keying.

Each was corrected only by reading the producer. A durable instrument prevents the next re-derivation, and gives the fold numbers instead of estimates.

The Architectural Reality

  • ai/configBase.mjs:528 / :537 — the two auth base-URL leaves; neither declares a custom metadata.parse.
  • ai/mcp/server/shared/services/AuthService.mjs:733 / :904 — the only normalization in the system, a trailing-slash strip duplicated at both consumer sites; providerBaseUrl is set from the stripped local while the leaf keeps its own spelling.
  • ai/ConfigProvider.mjs:321#applyEnvLayer calls decode(meta.env, {env, warn}), so parse receives the env var NAME, runs only in the env layer, and is skipped when a runtime override exists.
  • ai/mcp/server/memory-core/Server.mjs:577 — the durable AgentIdentity graph node id is normalizeAgentIdentityNodeId(userId), and userId is the provider login; :601 persists providerUserId as a property of that same row.
  • ai/graph/normalizeAgentIdentityNodeId.mjs — pure module, one argument, no provider coordinate.

The Fix

One spec, test/playwright/unit/ai/mcp/server/shared/services/ownerPrincipalNormalizationAxes.spec.mjs, asserting only present-tense facts. It uses createConfigProxy(Neo.create(RootConfigBase)) so assertions hit the real declarations rather than a replica leaf, and isolates by construction per ADR-0019 §4/B4 without mutating the shared singleton. Where no pure export exists the assertion is source-anchored with its bound stated in the spec.

Decision Record impact

aligned-with ADR 0019 — consumes §4/B4 isolation and §5.2 leaf-parser semantics; asserts no change to either.

Acceptance Criteria

  • The auth base-URL leaf is shown to normalize on no axis (trailing slash, case, default port, relative root)
  • Blast radius recorded: five spellings of one host resolve to five distinct principal coordinates, red-proved against a collapsed-class expectation
  • The two-reader divergence is pinned: one leaf, two spellings, strip living at two consumer sites
  • metadata.parse reach measured across all three entry points (env layer, leaf default, setEnvOverride)
  • Login-keyed ownership population sized: producers, comparison sites, and which stable fields already travel
  • First-write schedule pinned: the durable graph key and when it is first written
  • Every assertion is present-tense and selects no design option, so any landing normalization flips it deliberately

Out of Scope

  • Choosing frozen vs versioned normalization, or the transport mechanism — both belong to D#16764
  • Implementing the ownerPrincipal derivation itself, which stays with #16738
  • Changing any runtime behaviour; this leaf is test-only

Avoided Traps

  • A replica leaf. Declaring a lookalike leaf in the spec would assert the framework's behaviour rather than this repository's configuration — a test that cannot fail. The real RootConfigBase is constructed instead.
  • Importing a service to reach its logic. AuthService builds its verifiers inside factories and exports no pure normalizer; the unit-test workflow forbids importing a connect-on-init singleton for its logic, so those arms are source-anchored with the bound written into the spec.
  • Asserting a target shape. Encoding the expected post-fix behaviour would pin a decision the fold has not taken and would silently rot into a false contract.

Related

Refs #16738 · D#16764 · #15598 (whose Contract Ledger declared this normalization with a unit: base-url resolution spec evidence row that was never written) · ADR 0019

Live latest-open sweep: checked latest 20 open issues at 2026-08-09T12:31:14Z; no equivalent found. A2A in-flight sweep: no claim on this scope.

Retrieval Hint: "owner principal normalization witness matrix leaf parse reach first-write graph key login"

tobiu referenced in commit 231fb43 - "test(ai): witness matrix for owner-principal normalization and identity keying (#16782) (#16783) on Aug 9, 2026, 3:18 PM
tobiu closed this issue on Aug 9, 2026, 3:18 PM
tobiu closed this issue on Aug 9, 2026, 5:44 PM
tobiu referenced in commit b186cb2 - "test(ai): correct the blast-radius count — 4 principal coordinates, not 5 (#16782) (#16789) on Aug 9, 2026, 5:44 PM