fix: address code-review follow-up nits (confirm-stamp ordering, gate error classification, guest remap scope, RG existence check) - #41
Merged
Gregory Joseph (gnjoseph) merged 1 commit intoJul 9, 2026
Conversation
… error classification, guest remap scope, RG existence check) Four LOW-severity follow-ups from the PR #3 review, each small and surgical: 1. provision.ts - stamp the session confirmed as soon as the owning app is settled, BEFORE the billing-model / sub-RG elicitations can return an agent-guided ask and be re-invoked. Prevents the always-ask app gate from re-firing if the agent drops appSelection while answering a later billing prompt. The ownerScope gate is relaxed to key on resolved intent only (not session confirmation) so the earlier stamp does not suppress its ask. The confirmBilling financial-safety gate ordering is unchanged. 2. Control-plane mutation tools (create/register container type, app-grant add/remove, owner grant/revoke) - move resolveContextGate() INSIDE each handler's try so a stamp-write failure on contextChoice=confirm (writeState/writeSecureFile EACCES/EIO) is classified by the tool's own error handling instead of the generic dispatch catch. Early-return-on-gate behavior is unchanged. 3. container-type-permissions.ts - scope the guest-owner-rejection remap to the self-target (signed-in user) path only. An explicit member userId grant that fails for an unrelated reason mentioning "guest" now surfaces its raw reason instead of misdirected guest guidance. The proactive userType==="Guest" self-target check is preserved. 4. standard-billing-target.ts / azure-cli.ts - verify a user-entered NEW resource-group name (0-RG path) via a non-throwing resourceGroupExists probe (az group show). A non-existent RG now fails COST-FREE with actionable guidance before any container type / billing account is created, instead of only failing later at createSyntexAccount. An indeterminate probe (az missing / auth / transient) degrades to the prior behavior. The auto-select-singleton and multi-RG elicit paths are unchanged. Tests: gate-error-classification.test.ts (Nit 2) and standard-billing-target.test.ts (Nit 4) added; container-type-tools.test.ts (Nit 3), orchestration.test.ts (Nit 1), and provision-guided-billing.test.ts (Nit 4 integration) extended. Full suite: 731 passed | 3 skipped. lint / typecheck / build all clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Gregory Joseph (gnjoseph)
merged commit Jul 9, 2026
8e83795
into
feat/spe-mcp-server
5 checks passed
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.
Four LOW-severity follow-up nits from the PR #3 review — each small, surgical, and low-risk. Full pipeline green (
lint/typecheck/build/test), 731 passed | 3 skipped.The 4 nits
1. Stamp confirmed BEFORE billing elicitation (
src/tools/provision.ts) — robustnessPreviously the session was stamped confirmed only after the owning app was resolved, which ran after the billing-model / sub-RG elicitations. If the agent dropped
appSelectionwhile answering a later billing prompt, the always-ask app gate could re-fire.Fix: stamp the confirmation flag as soon as the owning app is settled (right after the app gate, before any billing/sub-RG elicitation can return-and-reenter). The
ownerScopegate is relaxed to key on resolved intent only (arg ?? state) — not session confirmation — so the earlier stamp doesn't suppress its ask. TheconfirmBillingfinancial-safety gate ordering (guided sub/RG → region check → confirmBilling → createSyntexAccount) is unchanged, and the app-gate always-ask semantics are preserved.Test:
orchestration.test.ts— app settled + a subsequent billing round-trip that omitsappSelectiondoes NOT re-return the app-selection ask.2. Move context gate inside the handler
try(control-plane mutation tools) — error classificationresolveContextGate(contextChoice)onconfirmcallsstampContextConfirmed→writeState→writeSecureFile, which can throw (EACCES/EIO). The gate was called above each handler'stry, so a stamp-write failure surfaced via the generic dispatch catch instead of the tool's own classifier.Fix: moved the gate inside the existing
try(still before the tool's main work) increate-container-type.ts,register-container-type.ts,container-type-app-grants.ts(add + remove), andcontainer-type-permissions.ts(owner grant + revoke). Early-return-on-gate behavior is identical.Test:
gate-error-classification.test.ts— withwriteStatemocked to throw, every gated handler called withcontextChoice=confirmreturns its own classifiedisErrorresult (not an unhandled throw).3. Scope the guest-owner error remap to the self-target path (
src/tools/container-type-permissions.ts)isGuestOwnerRejection(e)remapped any Graph error mentioning "guest"/"#ext#" to guest guidance — so an explicit memberuserIdgrant failing for an unrelated "guest"-containing reason got misdirected guidance.Fix: apply the guest-owner-rejection remap only when the target is the signed-in user (default self-target). Explicit-
userIdfailures surface the rawreason(e). The proactiveuserType === "Guest"self-target check is unchanged.Test:
container-type-tools.test.ts— explicit memberuserIdfailing with a "guest"-containing message → raw reason surfaced (NOT guest guidance); self-target guest rejection → guest guidance (existing behavior preserved).4. Verify a user-entered new resource-group name (
src/tools/standard-billing-target.ts) — fail cost-freeOn the 0-RG path the helper prompted for a NEW RG name and proceeded unverified; a typo/non-existent RG only failed later at
createSyntexAccount— after the container type existed. The server cannot create the RG.Fix: added a non-throwing
resourceGroupExists(name, subscriptionId)helper (src/azure-cli.ts,az group show) and probe the entered name. If it definitively does not exist → return actionable guidance (az group create ...then re-run) and fail cost-free before any CT/billing resource is created. An indeterminate probe (az missing / auth / transient) degrades gracefully to the prior behavior (proceed). Auto-select-singleton and multi-RG elicit paths are unchanged.Test:
standard-billing-target.test.ts(unit: missing → guidance/does-not-proceed; exists → proceeds/verified; indeterminate → proceeds/unverified; singleton + multi paths never probe) andprovision-guided-billing.test.ts(integration: 0-RG + missing entered name → cost-free guidance,createApplication/createContainerType/createSyntexAccountNOT reached).Guardrails honored
confirmBillinggate ordering, the app-gate/session core, or any tool names/schemas.Local pipeline
npm run lint✓ ·npx tsc --noEmit✓ ·npm run build✓ ·npm test→ Tests 731 passed | 3 skipped.