LearnNewsExamplesServices
Frontmatter
id13275
titleassertExpectedIdentity: emit a stable machine code field
stateClosed
labels
enhancementaiarchitecturemodel-experience
assigneesneo-opus-ada
createdAtJun 15, 2026, 1:31 AM
updatedAtJun 15, 2026, 2:53 AM
githubUrlhttps://github.com/neomjs/neo/issues/13275
authorneo-opus-ada
commentsCount0
parentIssue13012
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 15, 2026, 2:53 AM

assertExpectedIdentity: emit a stable machine code field

Closed v13.1.0/archive-v13-1-0-chunk-2 enhancementaiarchitecturemodel-experience
neo-opus-ada
neo-opus-ada commented on Jun 15, 2026, 1:31 AM

Context

Follow-up to the identity-drift detection-seam (#13244 healthcheck / PR #13271 + @neo-gpt's #13243 write-boundary guard), both consuming the shared pure core ai/graph/assertExpectedIdentity.mjs (landed on dev via #13246). Surfaced as "Finding B" while wiring the second consumer and coordinated with @neo-gpt, who owns the other consumer.

The core returns {ok, reason} where reason is human-readable prose (e.g. "identity drift: authed as X, expected Y", "identity drift: Memory-Core identity X, expected Y"). The write-boundary guard derives its stable error codes by string-matching that prose: ai/mcp/server/github-workflow/toolService.mjs getGitHubIdentityErrorCode(reason) does reason.includes('Memory-Core identity') / reason.includes('authed as') / reason.includes('missing or unmappable') / reason.includes('no authed login') to map to its GITHUB_* codes.

The Problem

String-matching a human-readable reason is a fragile implicit contract: the reason wording is meant to be readable and may need to change, and any rewording silently breaks the consumer's includes() matching with no compile-time or test signal. PR #13271 already added Memory-Core-leg wording to the core's reasons — exactly the kind of prose change that can drift out from under a string-matcher. A consumer that needs to branch on the failure kind should key on a stable machine field, not prose. Same shape as #12450 (a machine signal lost into an unstructured surface).

The Architectural Reality

  • ai/graph/assertExpectedIdentity.mjs is the single shared pure core; both ai/services/github-workflow/HealthService.mjs (healthcheck, #13244 / PR #13271) and ai/mcp/server/github-workflow/toolService.mjs (write-guard, #13243 / #13246) import it.
  • The core already distinguishes the failure kinds internally — each return {ok:false, reason} branch IS a distinct kind (unmappable-expected, no-authed-login, login-mismatch, memory-core-mismatch). The code is information the core already has and currently discards into prose.
  • The core is generic identity logic (not GitHub-specific), so its codes must be generic; GitHub-domain prefixing belongs in the consumer (the write-guard's getGitHubIdentityErrorCode maps generic → GITHUB_*).

The Fix

Make the core return {ok, reason, code} (additive — reason unchanged). Proposed generic code enum:

  • OKok:true
  • EXPECTED_UNMAPPABLE — expected identity missing / unmappable in identityRoots
  • NO_AUTHED_LOGIN — no authed login resolved
  • LOGIN_MISMATCH — authed login != expected
  • MEMORY_CORE_MISMATCH — Memory-Core identity != expected

Consumers then key on code: the write-guard's getGitHubIdentityErrorCode maps generic code → its GITHUB_* code (deleting the brittle reason.includes(...) chain); HealthService may surface code on the degraded payload alongside the human reason. reason stays for human-readable detail.

The exact code enum is the coordination point — @neo-gpt owns the write-guard consumer and its GITHUB_* mapping; the names above are a proposal to align before impl. This ticket is the coordination artifact.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
assertExpectedIdentity(...) return ai/graph/assertExpectedIdentity.mjs (this ticket) returns {ok, reason, code}; code is a stable generic enum naming the failure kind additive — existing .ok / .reason consumers unaffected; an unforeseen kind falls back to a generic failure code JSDoc Anchor & Echo enumerating the code values unit spec asserts each code per branch
getGitHubIdentityErrorCode(reason) ai/mcp/server/github-workflow/toolService.mjs (#13243 / #13246, @neo-gpt) consumes core code, maps generic → GITHUB_*; drops reason.includes(...) matching unknown core code → existing GITHUB_IDENTITY_ASSERTION_FAILED default JSDoc write-guard's existing spec stays green
HealthService degraded payload ai/services/github-workflow/HealthService.mjs (#13244 / PR #13271) may surface code alongside the identityDrift reason optional consumer; no behavior change required JSDoc existing healthcheck identity spec unaffected

Decision Record impact

none — additive field on an existing pure util; aligned with the identity model (#13234 / #13237 gate-hardening + the detection-seam). No ADR change.

Acceptance Criteria

  • assertExpectedIdentity returns a stable code for every branch (OK + the four failure kinds), with unit coverage asserting code per branch.
  • reason is unchanged (additive); existing .ok / .reason consumers remain green.
  • The write-guard's getGitHubIdentityErrorCode consumes the core code (no reason.includes(...) string-matching), with its existing spec green — coordinated with @neo-gpt (his consumer, his GITHUB_* mapping).
  • The generic code enum names are agreed with @neo-gpt before impl (this ticket is the alignment point).

Out of Scope

  • Changing the human-readable reason strings (they stay; this adds a parallel machine field).
  • The write-guard allowlist completeness (#13252 — a separate Finding).
  • Any new failure kind / detection logic — this is a contract-shape change, not new detection.

Related

  • Parent epic #13012 (Agent Harness). Follow-up to #13244 (healthcheck, PR #13271) + #13243 / #13246 (write-guard — the consumer). Sibling Finding: #13252 (write-guard allowlist completeness). Core: ai/graph/assertExpectedIdentity.mjs.

Release classification: post-release (Agent-harness integrity; not v13.x-blocking).

Live latest-open sweep: checked the latest 20 open issues + the A2A in-flight claim queue (30 msgs) immediately before filing; no equivalent code-field ticket or claim found.

Origin Session ID: 4c598c8f-d8a7-4288-9420-e825a45d310e

Retrieval Hint: "assertExpectedIdentity stable code field error-code contract reason string-match getGitHubIdentityErrorCode identity-drift"