Skip to content

feat(security): PrincipalGuard — cross-principal attribution detector (Know Your Principal #898, Phase 1)#902

Merged
JKHeadley merged 2 commits into
mainfrom
echo/principal-guard-phase1
Jun 6, 2026
Merged

feat(security): PrincipalGuard — cross-principal attribution detector (Know Your Principal #898, Phase 1)#902
JKHeadley merged 2 commits into
mainfrom
echo/principal-guard-phase1

Conversation

@JKHeadley

Copy link
Copy Markdown
Owner

What

The pure-logic detector brain of the "Know Your Principal" cross-principal coherence guard — the first implementation increment of the ratified standard (#898) and its spec (#897). Implements the §2 detector from OPERATOR-IDENTITY-BINDING-SPEC.md.

src/core/PrincipalGuard.ts:

  • establishOperator(uid, name?) — a topic's operator is established only from the authenticated sender id; there is no code path that accepts a name from content (the Caroline failure mode is impossible by type).
  • detectAttributions(text) — finds operator-role-decision shapes in agent-authored text: Mandate (X), X approved, locked with X, standing requirement from X, X dropped a token, on behalf of X.
  • evaluatePrincipalCoherence(text, operator, knownUserNames) — flags any attribution to a principal who is neither the bound operator nor a known user; blocks authority/credential misattributions (mandate, credential), warns on prose.

The incident-replay regression test (spec §test-plan)

The three real Caroline doc lines, with the topic bound to the operator, are all caught (block for the mandate + credential lines); and the same lines crediting the bound operator all pass (no false positives). Capitalized non-names ("Production approved", "The Board approved") are not flagged.

Scope

Pure logic, no runtime consumers yet — adding the file cannot change live behavior (see upgrades/side-effects/principal-guard-phase1.md). The later increments wire it into the topic-operator binding, the session-start "who is my operator" injection, and the outbound/at-rest review path. 13 unit tests, tsc clean.

ELI16

A detector that reads the agent's own writing and flags it whenever the agent credits a decision to a person who isn't the verified operator and isn't a known user — the structural catch for the Caroline failure, where my session credited my operator's decisions to a different real person and nothing noticed. It establishes who the operator is only from the platform-verified sender (never a name in a document), and it ships with a replay test built from the actual incident's three document lines.

Incident: CMT-1125. Standard: #898. Spec: #897.

🤖 Generated with Claude Code

… (Know Your Principal #898, Phase 1 brain)

Pure-logic detector half of the ratified Know Your Principal standard: establish
a topic operator ONLY from the authenticated sender (a content name can never
become the operator — by type), detect operator-role-decision attributions in
agent-authored text, and flag any credited to a non-bound/non-known principal
(block for mandate/credential, warn for prose). 13 unit tests incl. the
incident-replay regression (the real Caroline doc lines all caught; the same
lines crediting the bound operator all pass). No runtime consumers yet — wiring
into the topic-operator binding + session-start injection + review path are
later increments. Spec: docs/specs/OPERATOR-IDENTITY-BINDING-SPEC.md (#897);
incident CMT-1125.
@vercel

vercel Bot commented Jun 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
instar Ready Ready Preview, Comment Jun 6, 2026 6:41am

Request Review

…re docs-coverage class floor)

The new PrincipalGuard core module tipped the docs-coverage class floor (54% <
55%). Fix = document the capability properly: a public 'Know Your Principal'
concept doc on the docs site (the standard is ratified in the constitution) +
an internal module reference. Both mention PrincipalGuard; coverage back to 55%.
@JKHeadley JKHeadley merged commit 31901ee into main Jun 6, 2026
20 checks passed
JKHeadley pushed a commit that referenced this pull request Jun 6, 2026
…now Your Principal #898, increment 3)

The READ side of the operator binding and the first runtime consumer of
PrincipalGuard.evaluatePrincipalCoherence (#902). On the outbound delivery seam
(checkOutboundMessage), every finalized agent message is checked against the
topic's VERIFIED operator (TopicOperatorStore.asVerifiedOperator — the
authenticated-sender binding, never a content name). When the message credits an
operator-ROLE decision (approval / mandate / credential / lock / acting-for) to a
principal who is NOT the bound operator — the "Caroline" identity-bleed failure,
caught in the agent's OWN output — a structured finding is appended to
state/principal-coherence.jsonl.

SIGNAL-ONLY, modeled byte-for-byte on observeSelfViolation: fire-and-forget,
fail-open, dark by default (monitoring.principalCoherence.enabled, absent=off).
It NEVER blocks, delays, or rewrites the message; the recorded verdict is for
analysis only and is never enforced. Observe-first so the detector's
false-positive rate can be measured on real outbound before any warn/block
surface is built.

Tests (all three tiers, 14 total, green):
- unit  principal-coherence-operator-seam (5) — store->guard contract, both sides
- integ principal-coherence-signal (5) — over the wire, gating both sides
- e2e   principal-coherence-lifecycle (4) — production boot, signal-only proof

No new route/class/dependency. No migration needed (config read with ===true,
absent=off; mirrors the sibling correctionLearning flag's convention).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
JKHeadley added a commit that referenced this pull request Jun 6, 2026
…now Your Principal #898, increment 3) (#910)

The READ side of the operator binding and the first runtime consumer of
PrincipalGuard.evaluatePrincipalCoherence (#902). On the outbound delivery seam
(checkOutboundMessage), every finalized agent message is checked against the
topic's VERIFIED operator (TopicOperatorStore.asVerifiedOperator — the
authenticated-sender binding, never a content name). When the message credits an
operator-ROLE decision (approval / mandate / credential / lock / acting-for) to a
principal who is NOT the bound operator — the "Caroline" identity-bleed failure,
caught in the agent's OWN output — a structured finding is appended to
state/principal-coherence.jsonl.

SIGNAL-ONLY, modeled byte-for-byte on observeSelfViolation: fire-and-forget,
fail-open, dark by default (monitoring.principalCoherence.enabled, absent=off).
It NEVER blocks, delays, or rewrites the message; the recorded verdict is for
analysis only and is never enforced. Observe-first so the detector's
false-positive rate can be measured on real outbound before any warn/block
surface is built.

Tests (all three tiers, 14 total, green):
- unit  principal-coherence-operator-seam (5) — store->guard contract, both sides
- integ principal-coherence-signal (5) — over the wire, gating both sides
- e2e   principal-coherence-lifecycle (4) — production boot, signal-only proof

No new route/class/dependency. No migration needed (config read with ===true,
absent=off; mirrors the sibling correctionLearning flag's convention).

Co-authored-by: Instar Agent (echo) <echo@instar.local>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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