1. auth
temper
  • Temper documentation
  • 2026-07-06-cogmap-telos-differentiation
  • handoffs
  • plans
    • archived
    • evidence
  • reviews
  • specs
  • spikes
  • agents
  • auth
    • Temper auth & security
    • The authorization seam (`temper-services::auth`)
    • Cognitive-map & resource authoring authorization
    • JWT verification
    • The issuer / resource-server boundary & the machine-token contract
    • The internal reconcile channel
  • code-reviews
  • cognitive-maps
  • decisions
  • development
  • guides
    • Building a cognitive map from a large corpus
    • Using temper from Claude Desktop (and claude.ai)
    • Cloud Agent Development Guide
    • Ingesting a corpus into a context
    • Development setup
    • Drain operator queries (TraceQL)
    • Enterprise Install — Ground Up
    • Operator guide: read-only GitHub credential via a BYO App + Vercel Connect
    • Operator guide: provisioning a GitHub connection in temper
    • Installing Temper
    • Delivering L0 Kernel Cogmap Content
    • Machine Credentials
    • OpenTelemetry Setup
    • Operational Memory
    • Bootstrapping a Temper org
    • Releasing Temper
    • Self-Hosting Temper with Okta
    • Self-Hosting Temper with a SAML IdP
    • Self-Hosting Temper
    • The Slack Integration — identity, credentials, and what revocation actually means
    • Operator guide: `@temper` on Slack — end-to-end setup
    • Bootstrapping a team's self-cognition cognitive map
    • Working with Teams
    • Integrating Ruby with temper-rb
    • Deploying an Eve agent to Vercel (the steward and the citation auditor)
    • WS6 Collapsed-Schema Dev Environment
  • research
  • security
  • specs
  • doors
    • Building against Temper
    • Running Temper
    • Using Temper
  • Temper /api/query — the compositional read surface
    • Run a declared composition of situated acts.
    • Schemas
      • Composition
      • OutcomeDeclaration
      • ReturnSpec
      • Intention
      • StageNode
      • ActInvocation
      • CombineNode
      • StageInput
      • StageRelation
      • Disclosure
      • QueryResponse
      • StageResult
      • StageOutput
      • ScoreKind
      • Scoring
      • ResourceHit
      • CompositionTrace
      • StageTrace
      • InputSource
      • NarrowedBy
      • StageName
      • ActName
      • IdKind
      • IdSet
      • BoundTerm
      • Extent
      • StageDisposition
      • ActRefusal
      • PlanRefusal
      • RefusalReason
      • ActQuantity
      • QuantityScale
      • ResourceFilter
      • EdgeFilter
      • PropertyPredicate
      • PropertyOp
      • ResourceSection
      • EdgeKind
      • OrdOp
      • CogmapId
      • ContextId
      • IdProvenance
      • FacetPredicate
      • CombineOp
      • BlockId
      • MatchLocation
      • BodyStorage
      • ResourceId
      • IngestState
      • ManagedMeta
      • ProfileId
      • ResourceView
      • Polarity
      • ViaEntry
      • LensId
      • RegionId
      • CogmapRegionRow
      • RegionHit
      • StageInputTrace
      • Standing
      • ActorAuthority
      • Refusal
      • SystemAccessDetails
      • PlanRefusalDetails
      • ErrorDetails
      • ErrorDetail
      • ErrorBody
  • Temper Cloud API
    • Access
      • POST /api/access/requests — submit a join request for the gating team.
      • GET /api/access/requests/me — check own join request status.
      • DELETE /api/access/requests/me — withdraw a pending join request.
      • POST /api/access/reviews — a revoked principal asks an admin to reconsider (spec D15).
      • GET /api/access/settings — read public system settings.
    • Slack Link
      • Disconnect any principal. Operator path — offboarding and stuck users.
      • Disconnect EVERY Slack principal bound to the caller's own profile.
    • Auditor
      • auditor_dispatch
      • auditor_sweep
      • complete_auditor_job
    • Graph
      • POST /api/cogmaps/{id}/graph/slice — R4 cogmap-scoped neighborhood slice.
      • GET /api/graph/cogmaps/{id}/panorama — enter-a-cogmap Tier-0 interior.
      • GET /api/graph/contexts/composition — Beat E Tier-1: the force-graph composition of a container's (or a residual bucket's) members.
      • GET /api/graph/contexts/panorama — Beat E Tier-0: goal-container territories + residual tray.
      • GET /api/graph/home — the you→teams→cogmaps membership home.
      • GET /api/graph/regions/composition — Beat D region→resources composition drill.
    • Cognitive Maps
      • list_cognitive_maps
      • genesis
      • get_cognitive_map
      • reconcile
      • analytics
      • grant_cogmap_access
      • revoke_cogmap_access
      • materialize
      • materialize_delta
      • region_metrics
      • shape
      • bind_team
      • unbind_team
    • Contexts
      • list_contexts
      • create_context
      • get_context
      • context_materialize
      • reassign
      • context_region_metrics
      • rename
      • context_shape
      • share_team
      • unshare_team
    • Events
      • cursor
      • GET /api/graph/elements/{kind}/{id}/trail — R5 element event-trail. kind ∈ {node, edge}.
    • Facets
      • set_facet
      • Read the live facets of one edge.
      • Set a facet whose owner is an **edge** rather than a resource.
      • Read the live facets of one resource — the confirming read for a write that steers region formation and Atlas grouping.
    • Health
      • health_check
    • Ingest
      • create_ingest
      • update_ingest
      • list_blocks
      • append_block
      • finalize_resource
    • Invitations
      • accept
      • decline
      • list_mine
      • list_team_invitations
      • revoke_team_invitation
      • create_team_invitation
    • Invocations
      • list_invocations
      • open
      • show
      • close
    • Profile
      • get_profile
      • update_profile
      • list_auth_links
    • Query
      • `POST /api/query`.
    • Relationships
      • assert
      • fold
      • retype
      • reweight
    • Resources
      • `GET /api/resources` — **one response type, unconditionally.**
      • create_resource
      • get_resource
      • delete_resource
      • update_resource
      • List the finding at `{id}`'s citation-audit trail — one row per audit, each naming its auditor.
      • Record an auditor's signed defensibility verdict on one `(block, source)` citation of the finding at `{id}`. CONFORM to `handlers::edges::assert` (the sibling authored-write handler): thin — build the command, dispatch it, map the error. No persistence he
      • get_content
      • list_resource_edges
      • resource_evidence
      • grant_resource_access
      • revoke_resource_access
      • resource_lineage
      • provenance
      • annotate_resource
    • Meta
      • get_meta
      • update_meta
    • Reassign
      • reassign_resource
      • reassign_team
    • Search
      • `POST /api/search`.
    • Steward
      • candidates
      • dispatch
      • sweep
      • delta
      • advance
    • Teams
      • list_teams
      • create_team
      • detail
      • delete_team
      • update_team
      • add_member
      • remove_member
      • change_role
    • Schemas
      • AcceptInvitationResponse
      • ActInput
      • ActInvocation
      • ActName
      • ActQuantity
      • ActRefusal
      • ActorAuthority
      • AddMemberRequest
      • AdvanceWatermarkAck
      • AdvanceWatermarkRequest
      • AgentAuthorship
      • AppendBlockPayload
      • AssertRelationshipRequest
      • AtlasEdge
      • AtlasHome
      • AtlasNode
      • AtlasSubgraph
      • AuditCitation
      • AuditSweepRow
      • AuditorDispatchTickRequest
      • AuditorDispatchTickResponse
      • AuditorJobCompleteAck
      • BindTeamOutcome
      • BindTeamRequest
      • BlockId
      • BlockProvenanceRow
      • BlocksResponse
      • BodyStorage
      • Bridge
      • BulkReassignAck
      • BulkReassignRequest
      • ChangeRoleRequest
      • CharterBlock
      • CharterDisposition
      • CitationAuditRequest
      • CitationAuditRow
      • ClaimedAuditJob
      • ClaimedJob
      • CloseInvocationRequest
      • CogmapAnalyticsRow
      • CogmapDetail
      • CogmapFoundationRow
      • CogmapGrantBody
      • CogmapId
      • CogmapRegionMetricsRow
      • CogmapRegionRow
      • CogmapRegulationRow
      • CogmapRevokeBody
      • CogmapRow
      • CogmapStaleness
      • CombineNode
      • CombineOp
      • Composition
      • CompositionTrace
      • ConfidenceBand
      • ContentResponse
      • ContextCreateRequest
      • ContextId
      • ContextOwnerRef
      • ContextPanorama
      • ContextRow
      • ContextRowWithCounts
      • CorrelationId
      • CreateCogmapOutcome
      • CreateCogmapRequest
      • CreateInvitationRequest
      • CreateRequestBody
      • CreateReviewBody
      • DeleteResponse
      • DeviceOverrides
      • DispatchTickRequest
      • DispatchTickResponse
      • Disposition
      • DriftSweepRow
      • EdgeFacetRow
      • EdgeFacetSetRequest
      • EdgeFacetsResponse
      • EdgeFilter
      • EdgeId
      • EdgeKind
      • ElementEvent
      • ElementKind
      • EmbedDispatchSummary
      • Entitlements
      • ErrorBody
      • ErrorDetail
      • ErrorDetails
      • EventCursorResponse
      • EventTrail
      • ExactArm
      • ExactHit
      • Extent
      • FacetAck
      • FacetPredicate
      • FacetSetRequest
      • FinalizePayload
      • FoldRelationshipRequest
      • GrantOutcome
      • GraphEdgeRow
      • GroupKeyMeta
      • HealthResponse
      • HomeCogmap
      • HomeContext
      • IdKind
      • IdProvenance
      • IdSet
      • IdpRevocation
      • IngestCreateResponse
      • IngestDelta
      • IngestPayload
      • IngestState
      • InheritedReadGrant
      • InheritedShare
      • InputSource
      • Intention
      • InvitationStatus
      • InvitationTokenRequest
      • InviteeInvitation
      • InvocationAck
      • InvocationActRow
      • InvocationCloseAck
      • InvocationId
      • InvocationSummary
      • InvocationView
      • JoinRequest
      • JoinRequestStatus
      • LensId
      • LineageNode
      • ManagedMeta
      • MatchLocation
      • MaterializeAck
      • MaterializeDelta
      • MaterializeRequest
      • MergePolicy
      • MetaUpdatePayload
      • NarrowedBy
      • NodeHome
      • OpenInvocationRequest
      • OrdOp
      • OrphanNode
      • OutcomeDeclaration
      • PlanRefusal
      • PlanRefusalDetails
      • Polarity
      • Profile
      • ProfileAuthLink
      • ProfileId
      • ProfileUpdateRequest
      • ProfileWithEntitlements
      • PropertyOp
      • PropertyPredicate
      • ProvenanceSource
      • PublicSystemSettings
      • QuantityScale
      • QueryResponse
      • ReassignAck
      • ReassignContextOutcome
      • ReassignContextRequest
      • ReassignResourceRequest
      • ReconcileCogmapRequest
      • ReconcileEdge
      • ReconcileEdgeTombstone
      • ReconcileEntry
      • ReconcileOutcome
      • ReconcileTelos
      • ReconcileTelosBlock
      • ReconcileTombstone
      • Refusal
      • RefusalReason
      • RegionHit
      • RegionId
      • RelationshipAck
      • RemoveMemberOutcome
      • RenameContextOutcome
      • RenameContextRequest
      • ResidualBucket
      • ResidualContext
      • ResidualGroups
      • ResidualOwnedReach
      • ResourceAnnotateRequest
      • ResourceCreateRequest
      • ResourceFacetRow
      • ResourceFacets
      • ResourceFacetsResponse
      • ResourceFilter
      • ResourceGrantBody
      • ResourceHit
      • ResourceId
      • ResourceLineage
      • ResourceListResponse
      • ResourceRevokeBody
      • ResourceSection
      • ResourceSortField
      • ResourceUpdateRequest
      • ResourceView
      • ReturnSpec
      • RetypeRelationshipRequest
      • RevokeOutcome
      • ReweightRelationshipRequest
      • ScoreKind
      • Scoring
      • SearchParams
      • SearchReason
      • SearchResponse
      • SearchResultRow
      • SearchScope
      • SearchScopeInfo
      • SegmentInfo
      • SegmentedBegin
      • SegmentedBeginResponse
      • ShareContextOutcome
      • ShareContextRequest
      • SlackDisconnectRequest
      • SlackDisconnectResponse
      • SlackDisconnectedPrincipal
      • SliceRequest
      • SortOrder
      • StageDisposition
      • StageInput
      • StageInputTrace
      • StageName
      • StageNode
      • StageOutput
      • StageRelation
      • StageResult
      • StageTrace
      • Standing
      • StandingShape
      • Subscription
      • SubscriptionOverride
      • SystemAccessDetails
      • TeamCreateRequest
      • TeamDetail
      • TeamInvitation
      • TeamMemberDetail
      • TeamMemberRow
      • TeamMemberSource
      • TeamRole
      • TeamRow
      • TeamUpdateRequest
      • Territory
      • TerritoryKind
      • TerritoryOverview
      • UnbindTeamOutcome
      • UnshareContextOutcome
      • VaultConfig
      • ViaEntry
      • WideArm
      • WideHit
  1. auth

Cognitive-map & resource authoring authorization

This is the per-resource authorization axis: given an authenticated caller, what
may they author?
It is distinct from the authorization seam,
which answers the prior question — may they use Temper at all? (authenticate → system
access). A caller passes the seam first; then every write is gated again, per target,
by the predicates below.

The one thing to remember#

Authoring is an explicit capability, never obscurity. A cognitive map has no
owner column
— since the Q-A flip (20260701000001_cogmap_write_tightening.sql),
authorship is wholly an explicit write grant. Team membership grants read, not
write. Knowing a cogmap id gets you nothing: without a kb_access_grants write row (or
being a resource's own owner/originator) every authoring call is denied.
Verified live 2026-07-06: a principal with read on the team map 019f2391 (via
membership) but no write grant was denied fold_relationship ("cannot modify this
resource") and could not self-grant (cogmap_grant → granted:false). The only
write-holder is the steward's granted M2M principal.

The three predicates#

All three are SQL functions resolved against the connection search_path; surfaces and
DbBackend call them, never inlining the SQL.
PredicateQuestionDefinition
cogmap_authorable_by_profile(profile, cogmap)May profile author into this map?profile_explicit_grant(profile, 'write', 'kb_cogmaps', cogmap) — explicit write grant only (cogmaps have no owner)
context_authorable_by_profile(profile, context)May profile author into this context?personal-owner, reachable-member-of-owning-team, or an explicit can_write grant
can_modify_resource(profile, resource)May profile modify this existing resource?resource's home owner/originator, an explicit per-resource (kb_access_grants, can_write) grant, or write on the resource's home container (cogmap_authorable_by_profile / context_authorable_by_profile) — the container-write cascade
anchor_readable_by_profile(profile, 'kb_cogmaps', cogmap)May profile read this map?membership-broad read visibility
can_modify_resource consults the resource's own ownership/grants and its home
container's write capability (the cascade, below). An existing cogmap node is therefore
modifiable by its originator, by any co-author who holds write on the map, or via an
explicit per-resource grant — but not by an arbitrary map reader.

The container-write cascade#

Whoever may author a container may modify any node homed in it — unix directory
semantics: directory-write ⇒ file-rwx. A cogmap co-author (holder of
cogmap_authorable_by_profile) or a context writer (context_authorable_by_profile)
can create nodes and fold/facet/assert-from/update nodes another principal
originated, without a per-resource grant. This is deliberate collaborative stewardship:
gating node-modify on node-ownership alone was illusory anyway, since a container-writer
could already supersede a node by fold-then-recreate. Provenance is unaffected — the
event ledger records the actual actor on every mutation, so "co-author B folded A's node"
reads truthfully.
context_authorable_by_profile's team-owner arm (a member of the owning team may
author a team-owned context) is deliberate and is not the pre-Q-A "membership implies
write". Q-A removed write for teams merely joined-for-read to a cogmap; owning a
context is a strictly stronger relationship. (Spec:
internal/superpowers/specs/2026-07-06-container-write-cascade-and-authz-hardening-design.md.)

The gate map — every authoring op#

OperationGateEnforced in
create_resource into a cogmapcogmap_authorable_by_profile (write grant)DbBackend::create_resource (F1) + the surfaces (MCP create_resource tool + HTTP ingest) as fast-fail pre-checks, via the shared cogmap_service::authorable_by_profile seam
assert_relationshipcan_modify_resource(source) — incl. container cascadeDbBackend::check_can_modify_next
fold_relationship / retype / reweightcan_modify_resource(source) — incl. container cascadeDbBackend::check_can_modify_next
facet_setcan_modify_resource(resource) — incl. container cascadeDbBackend::check_can_modify_next
update_resource / delete_resourcecan_modify_resource(resource) — incl. container cascadeDbBackend::check_can_modify_next
advance_steward_watermarkcogmap_authorable_by_profile (write grant)DbBackend
materialize / materialize_deltacogmap_authorable_by_profile (write grant)DbBackend
invocation_open (self-attributed, parent = None)cogmap_authorable_by_profile — WRITE (F2)DbBackend::check_cogmap_authorable
invocation_open (delegated, parent = Some)anchor_readable_by_profile — READ; substrate enforces parent→originating lineageDbBackend::check_can_read_cogmap
Note the two homes: content writes on existing resources gate inside DbBackend
(can_modify_resource, which now cascades from container write); create-into-cogmap
also gates inside DbBackend (F1) — the surfaces keep a matching pre-check for fast-fail
and clearer error text, but the shared write path is the authoritative gate, so a new
caller cannot bypass it.

Cross-surface uniformity#

The create-into-cogmap gate is defined once in cogmap_service::authorable_by_profile
and called by both the MCP tool and the HTTP ingest handler — so MCP, CLI (which routes
resource create → POST /api/ingest), and API all enforce the same rule. DbBackend
is the single write path for every other op, so those gates are surface-uniform by
construction.

Agent vs human principals#

Agents are gated identically to humans. The steward is an M2M principal
(client_credentials); it authors 019f2391 because it holds an explicit write
grant
, exactly the mechanism a granted human would use — not by virtue of any team
membership, since membership confers read only (the Q-A flip). There is no
agent-specific bypass and no ambient authority: every call resolves to one concrete
profile_id, and every gate evaluates that id.
An agent profile can hold team memberships — registration takes --team <ref>[:role]
(repeatable) and also enrolls the machine in the gating team as watcher, so it clears the
system_access gate. That is the point of the design: a machine's reach is ordinary teams
and ordinary grants, bounded to what its minter could confer on a human, so machine RBAC
falls out of the same predicates as human RBAC
— there is no machine-specific
authorization path to keep in sync. What team membership still does not buy an agent, any
more than it buys a human, is cogmap write. See
../guides/machine-credentials.md and the
machine-token contract.
When a human drives an agent (e.g. an AI assistant over the human's authenticated MCP
session), the session authenticates as the human's principal — there is no separate
"assistant" principal. The assistant's tool calls carry the human's rights, no more.

Hardening — resolved#

The three findings once tracked here are shipped (none was ever a live open door; all were
defense-in-depth / clarity). Recorded for provenance.

F1 — create-into-cogmap authz moved onto the shared write path ✅#

DbBackend::create_resource now checks cogmap_authorable_by_profile on a Cogmap home
(check_cogmap_authorable), before any write — so the shared write path denies even a
caller that skipped a surface pre-check (the SAML is_active failure mode this directory
exists to prevent). The surfaces keep the pre-check for fast-fail + clearer error text.

F2 — invocation_open is write-gated for self-attributed opens ✅#

A self-attributed open (parent = None) now requires cogmap_authorable_by_profile
(WRITE) — claiming a ledger slot under one's own name is an authoring act, closing the
reader-posts-inert-envelopes noise vector. A delegated open (parent = Some) keeps the
READ gate, with the substrate's parent→originating lineage as the control for delegated
sub-agents. In production the only self-attributed opener is the steward, which holds
write, so no real caller regressed.

F3 — stale "team-cogmap membership" comments corrected ✅#

The three seam comments (temper-mcp/.../resources.rs, temper-api/.../ingest.rs,
cogmap_service.rs) now name cogmap_authorable_by_profile = an explicit write grant
(membership confers read only, per Q-A), and note the F1 backend re-enforcement.
Modified at 2026-08-19 17:59:52
Previous
The authorization seam (`temper-services::auth`)
Next
JWT verification
Built with