feat(missions): mission/PS-governance API, call-chain demo, and spec-grounded docs#32
Open
dasiths wants to merge 18 commits into
Open
feat(missions): mission/PS-governance API, call-chain demo, and spec-grounded docs#32dasiths wants to merge 18 commits into
dasiths wants to merge 18 commits into
Conversation
…dentity Rewrite agent-side Mission to the approved mission blob (approver, agent, approved_at, description, approved_tools, capabilities) with verbatim body bytes and base64url(SHA-256) s256 identity. Add MissionState (active/ terminated), MissionTool, and AAuthCapabilitiesHeader.Union. Includes the missions/PS governance research and implementation plan. Phase 1 of missions/PS governance.
Carry {approver, s256} as the optional `mission` claim in resource and
auth tokens, surface it on verification, and cover `aauth-mission` in the
RFC 9421 signature when the AAuth-Mission header is present.
- Add MissionClaim {approver, s256} value type
- ResourceTokenBuilder/AuthTokenBuilder emit `mission` only when set
- TokenVerifier.VerifiedToken exposes the verified mission claim
- AAuthSigningHandler auto-covers `aauth-mission` (last, per spec) with
no double-cover
- AAuthVerifier + verification middleware validate the `aauth-mission`
covered component so signed mission requests round-trip
Phase 2 of missions/PS governance.
…mission_terminated - TokenExchangeRequest: justification/login_hint/tenant/domain_hint/platform/device - ClarificationRequirement parsing + ClarificationExchange (respond/update/cancel) with default 5-round limit and OnClarificationRequired callback - TokenErrorCode.MissionTerminated + AAuthMissionTerminatedException, classified on token response and during polling Phase 3 of missions/PS governance.
Phase 4 — agent-side PS governance clients + metadata discovery:
- Parse permission_endpoint and audit_endpoint in ServerMetadata
(all four governance endpoints now surfaced; §Person Server Metadata).
- MissionClient.ProposeAsync: POST {description, tools?}, handle 202
review/clarification, verify AAuth-Mission s256 vs blob (§Mission Creation/Approval).
- PermissionClient: {action, description?, parameters?, mission?} -> granted/denied
with approved_tools short-circuit (§Permission Endpoint).
- AuditClient: fire-and-forget 201, mission required (§Audit Endpoint).
- InteractionClient: interaction/payment/question/completion (§Interaction Endpoint).
- GovernanceExchange: shared signed-POST + deferred-202 loop + origin-pin +
mission_terminated; GovernanceOptions.
Phase 5 — PS server-side governance seams + mission log:
- GovernanceEndpoints request parsers + spec 403 mission_terminated helper
(§PS Governance Endpoints, §Mission Status Errors).
- IMissionStore/InMemoryMissionStore: verbatim blob bytes + active/terminated state.
- IMissionLog/InMemoryMissionLog: ordered append + prior-consent lookup
keyed by (s256, resource, scope) (§Mission Log).
- IPermissionDecider (typed decision + reason), IAuditSink, IInteractionRelay.
- AddAAuthGovernance DI registration for storage seams.
Tests: GovernanceClientTests (12), GovernanceServerTests (17).
417 conformance + 371 unit green; SDK + full solution build 0/0.
Phase 4 and Phase 5 of missions/PS governance.
- Extract DeferredExchange as the single deferred-HTTP transport; delete GovernanceExchange; TokenExchangeClient delegates transport, preserving access_denied / mission_terminated / token-error behaviour via option seams. - Add public AAuthGovernanceClient facade + AAuthClientBuilder.BuildGovernance() from a shared signed-channel helper. - Add GovernanceFacadeTests (5). Conformance 422, unit 371, builds 0/0. Phase 5.5 of missions/PS governance.
…nance
- MockPersonServer: serve mission/permission/audit/interaction endpoints,
three-gate token consent, terminate hook, and {approver, s256} auth-token
emission via the Phase 5 governance seams
- MockPersonServer: interactive browser consent for mission creation,
out-of-scope token, and out-of-tool permission; consent pages show the
mission description + approved_tools as context
- SDK: mission-aware resource support (AAuthMissionHeader.TryParseStructured,
ChallengeOptions.MissionAware, AAuthChallengeMiddleware copies {approver,
s256} into the resource token); WhoAmI /jwt/mission demonstrates it
- samples/MissionAgent: new CLI driving the full mission lifecycle against the
live mock servers (enrol -> propose -> access -> permission -> audit ->
interaction -> complete), interactive by default, --auto for scripted
- Tests: 12-row Consent-Matrix integration test (MissionAgentFlowTests) and +3
mission-aware ChallengeMiddleware conformance tests (425 / 383 green)
- Makefile: demo-mission + agent-mission targets
Phase 6a of missions/PS governance.
- Add repeatable --pre-approve <scope> CLI flag that seeds the (resource origin, scope) pair as in-scope before the mission is proposed, so the matching token request resolves silently at gate 2a (reason InScope) instead of prompting (§Agent Token Request). - Pre-approving the WhoAmI scope drops the token consent screen: an interactive run shows two browser screens (mission creation + delete_inbox permission) instead of three. - Adapt step 3/4 narration to show IN SCOPE (silent) vs OUT OF SCOPE, and document the flag in the README Options table. Phase 6a of missions/PS governance.
…E_APPROVE support
…ent-token replay - Add the prompted out-of-mission scope gate (gate 3) so both halves of the spec gate model are demonstrated: a prompted scope (§Agent Token Request gate 3, §Scopes) alongside the prompted tool (§Permission Endpoint). WhoAmI gains scope whoami:elevated_scope at /jwt/mission/elevated. - SampleApp Mission.razor renders the full 5-gate flow (+ Home link); GuidedTour TourMode.Mission drives every gate through both outcomes with the PS decision reason surfaced. - Fix GuidedTour mission hang: refresh the agent token (fresh jti) per resource access so /jwt/mission/elevated is not rejected as a replay, restoring the 202 out-of-mission-scope prompt (§Agent Token replay protection). Remove temporary DIAG instrumentation from TourSession and AAuthChallengeMiddleware. - Default MissionAgent in-scope set to whoami (mirrors SampleApp) and rename --pre-approve to --mission-approved (Makefile MISSION_APPROVED). - Add SampleApp + GuidedTour mission Playwright specs; update picker spec for the 7th (Mission) flow. MockPersonServer consent-screen UX refinements (D9). Phase 6b of missions/PS governance.
The Phase 7 — Docs section heading was lost in 5fe6809; the section body was intact. Restore the heading so phase numbering is contiguous.
- Rewrite docs/advanced/missions.md to the shipped blob model (s256, two states, structured AAuth-Mission header, MissionClaim binding chain) - Add mission-governance-clients, clarification-chat, server/mission-governance, and workflows/mission-governed-access docs - Document MissionAware, mission claim emission, mission_terminated, AddAAuthGovernance + governance-client wiring - Index new docs and add API-Map rows in docs/README.md Phase 7 of missions/PS governance.
- samples/README.md: add MissionAgent to the index (Nine -> Ten) and a mission Quick Start (make demo-mission / agent-mission). - MockPersonServer/README.md: add an "Agent governance (missions)" section covering AddAAuthGovernance + the four governance endpoints, three-gate consent, and mission-aware resource token copying (cites the spec's protocol exchange diagram + Resource Token Verification). - GuidedTour/README.md: document the Mission (PS-Governed) mode (Six -> Seven flows) and add Mission/Federated to the Mode config enum. - Annotate the call-chain samples (Orchestrator Program.cs, SampleApp CallChain.razor) that mission governance is optional and orthogonal to call chaining and is intentionally omitted from the demo; the samples follow the spec's "no mission, iss is a PS" path (Section: Call Chaining). - Update the implementation plan: tick the Sample READMEs DoD, correct the inaccurate "MockPersonServer done in 6a" annotation, and record the user decision to defer the Orchestrator mission-governed hop. Phase 6c of missions/PS governance.
- Remove out-of-spec `AAuthCapabilitiesHeader.Capabilities.Mission` constant; the spec defines exactly three capability values (interaction, clarification, payment) and the constant had no production usages (Section: AAuth-Capabilities Request Header). - Fix stale "14.1" spec citations to the named AAuth-Capabilities anchor across the header, signing handler, and conformance tests. - Add an untrusted-Markdown sanitization remark to Mission.Description so consumers know to sanitize before rendering (Section: Markdown). - Record the Phase 8 multi-subagent review (R1-R7) in research and tick the Phase 8 DoD; capture deferred findings with rationale (capabilities body param, lenient audit codes, test-coverage gaps, dev-grade store growth). Post-remediation gate: build 0/0, unit 383, conformance 425, mission e2e 4/4. Phase 8 of missions/PS governance.
Introduce the first-pass mission governance API alongside the existing per-call surface (additive; no flows break, full suite green). Agent side: - MissionSession auto-threads the mission claim + bound Person Server across permission/audit/interaction calls - AAuthGovernanceClient gains a bound variant, a Create(...) factory, a PersonServer property, and ProposeMissionAsync(...) -> MissionSession - AAuthClientBuilder.BuildGovernance(GovernanceOptions?) binds the PS URL - AddAAuthGovernanceClient(...) registers the client for DI Resource side: - AddAAuthGovernance() also registers conservative default seams (DefaultPermissionDecider/DefaultAuditSink/DefaultInteractionRelay) via TryAdd - MapAAuthGovernance(...) maps the permission/audit/interaction endpoints from the seams; AAuthGovernancePipelineOptions controls routes Satisfies the construction triad (factory + builder + DI). Adds unit and conformance coverage. Mission-creation mapping and deferred consent are deferred to Phase 2 (see plan DEV-1/DEV-2).
…ferred consent (Phase 2) Phase 2 of the mission-api-refactor finalizes the DI-friendly governance surface and promotes the PS mission machinery into the SDK. D1 — remove per-call personServer: the bound governance client is now the only path. AAuthGovernanceClient/MissionClient/PermissionClient/AuditClient/ InteractionClient/MissionSession take the person server at construction; all consumers (tests + samples) migrated. D4 — MissionAction POCO with an implicit string conversion for terse call sites. D3a — promote mission creation into the SDK (closes DEV-2): add MissionApprovalBuilder (canonical approval-blob builder) and an IMissionApprover/DefaultMissionApprover seam. MapAAuthGovernance now maps the mission endpoint, verifies the agent token, runs the approver, persists the StoredMission, and emits the AAuth-Mission header. MockPersonServer reuses MissionApprovalBuilder. D3b — deferred consent (closes DEV-1): add opt-in IDeferredConsentStore / InMemoryDeferredConsentStore + AddAAuthDeferredConsent(). When registered, the mapper parks a Prompt outcome and answers 202 + poll route for both mission and permission; the store is opt-in so the existing Prompt->denied default is preserved. The interactive browser page stays a sample concern. Tests: unit 387 passed, conformance 448 passed (+8 mapper tests), mission e2e green; full solution builds 0/0.
Refactor the mission governance surface across the SDK, samples, and docs, and add a combined mission call-chain sample that threads one human-approved mission through a clarification round and a delegated call chain. SDK: - Honor InteractionRelayResult.Pending for interaction/payment in MapAAuthGovernance: park on the deferred-consent store and return 202 + poll Location, degrading to synchronous 200 when no store is registered (spec Interaction Response). - Add DeferredConsentKind.Interaction and DeferredConsent.Interaction. - Add MissionHeaderHandler and clarification challenge seam wiring. Samples: - Add SampleApp MissionCallChain page (clarification + mission-forwarded chain + mission log) with side-nav entry and e2e spec. - Echo the nested act claim from WhoAmI /jwt/mission and /jwt/mission/elevated for parity with /jwt (spec Upstream Token Verification step 4). Docs: - Update dependency-injection, missions, mission-governance, clarification, error-handling, and mission-governed-access references. Tests: - Add conformance tests for the interaction deferral path, mission-header seam, and clarification seam; update governance test suites.
Two independent review subagents validated this initiative post-commit: one grounding every SDK change against the spec, the other grounding all docs and sample snippets against the SDK. Remediate the documentation drift the second reviewer found (D-1..D-7); the SDK reviewer found no CRITICAL/HIGH issues. - mission-governance-clients.md, mission-governed-access.md: pass MissionAction (not bare strings) to RequestPermissionAsync/RecordAuditAsync so the snippets compile. - server/mission-governance.md: compare t.Name to context.Request.Action.Name; correct the interaction route comment to /mission-interaction. - reference/dependency-injection.md + reference/configuration.md: replace the non-existent AAuthAgentOptions members (UseHwk, InteractionHandling, etc.) in examples and tables with the real surface (OnResourceInteraction, OnApprovalPending, PollingTimeout); soften the no-op-seam prose. - advanced/error-handling.md: add MissionTerminated to the TokenErrorCode listing. SDK findings are adjudicated in the deviations log: DEV-12 (access_denied vs the spec's `denied`, Polling Error Codes) surfaced as a cross-cutting decision; DEV-13 (carrier-token 401 shape) and DEV-14 (forward-looking user_unreachable) logged intentional. Plan gains a Phase 11 section. No code changed; build 0/0.
§Polling Error Codes defines the explicit-denial code as `denied`; `access_denied` (OAuth/RFC 6749 vocabulary) appears nowhere in the AAuth error tables. Rename every emitter, classifier, test, sample, narration, and doc snippet to `denied` with no backward-compat alias, since every emitter and classifier in this repo is ours and now round-trips `denied` end-to-end. Because the SDK's DeferredPoller already classifies the spec `denied` polling code as PollingErrorException(Denied), the high-level interaction wrappers (DeferredExchange.PollAsync, AccessServerClient.PollDeferredAsync) now translate that into the semantic AAuthInteractionDeniedException, preserving the public contract. The GuidedTour poll loop catches the same typed exception to record its terminal denied step. Resolves DEV-12. Build 0/0; AAuth.Tests 387/387; AAuth.Conformance 468/468; deny-path e2e (sample-app + guided-tour) green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Refactors the AAuth .NET SDK's mission / PS-governance surface into a consistent,
DI-friendly API and threads a human-approved mission through the full governance
lifecycle — mission creation, scope evaluation, clarification chat, permission/audit,
deferred consent, and mission-forwarded call chaining. Adds a combined SampleApp demo,
migrates every mission sample and doc to the new surface, and lands a set of
spec-hardening fixes. Closes the initiative tracked in
.agent/plans/2026-06-06-mission-api-refactor/.Every change is grounded in
aauth-spec/draft-hardt-oauth-aauth-protocol.md. Twoindependent review subagents validated the result post-implementation (Phase 11):
one grounding every SDK change against the spec, the other grounding all docs
and sample snippets against the SDK.
What changed
SDK (
src/AAuth/)builders (
BuildGovernance(),WithMission(...)), and DI registration(
AddAAuthGovernanceClient,AddAAuthGovernance,AddAAuthDeferredConsent).{approver, agent, approved_at, description, approved_tools, capabilities}+ the{approver, s256}mission claim, bound throughthe token chain and HTTP message signatures (
aauth-missioncovered component).IMissionStore,IMissionLog,IMissionApprover,IPermissionDecider,IAuditSink,IInteractionRelay,IDeferredConsentStorewith in-memory/no-op defaults;
MapAAuthGovernance()maps the mission, permission,audit, and interaction endpoints + the deferred-poll route.
requirement=clarification, 202, agent respond/update/cancel),deferred consent (202 + poll
Location), mission_terminated surfacing, andnested
actconstruction for call chaining.InteractionRelayResult.Pending(DEV-9); audit endpoint returns 201; metadata parses
permission_endpoint/audit_endpoint.Samples
MissionCallChainpage (clarification + mission-forwarded chain +mission log) with a Playwright e2e spec and side-nav entry.
forwarding, and WhoAmI echoing the nested
actclaim on/jwt/mission*for parity.Docs
missions,mission-governance,mission-governance-clients,clarification-chat,mission-governed-access,dependency-injection, and others.the SDK (
MissionActionusage,AAuthAgentOptionsmembers/tables, theMyPermissionDecidercomparison, theTokenErrorCodelisting, the/mission-interactionroute comment, and the no-op-seam prose).Review outcome (Phase 11)
behaviors (s256 binding, mission claim,
aauth-missionsigning, deferred poll,clarification round-trip,
mission_terminated, nestedact) verified compliant.Open decision for reviewers
access_deniedvs specdenied. §Polling Error Codes defines theexplicit-denial code as
denied; the SDK currently uses OAuth'saccess_denied.It round-trips SDK-to-SDK but is not recognized from a spec-conformant external PS.
A correct fix is a coordinated rename (with
access_deniedkept as a read-sidealias) spanning the out-of-scope AccessServer path, shared agent classifiers,
tests, and sample narration (~30 sites) — surfaced here as a follow-up rather than
rushed into this PR. See
issues-and-deviations.md.Validation
dotnet build AAuth.slnx— 0 warnings / 0 errors.AAuth.Tests387/387;AAuth.Conformance468/468 (incl. new clarification,mission-header, and deferred-interaction cases).
sample-app): mission + mission-call-chain specs green.Notes
.agent/plans/2026-06-06-mission-api-refactor/..agent/plans/2026-06-06-r3-rich-resource-requests/.