diff --git a/plugins/gs-superadmin/.claude-plugin/plugin.json b/plugins/gs-superadmin/.claude-plugin/plugin.json index 48cd155..f9c8731 100644 --- a/plugins/gs-superadmin/.claude-plugin/plugin.json +++ b/plugins/gs-superadmin/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "gs-superadmin", - "version": "0.38.0", + "version": "0.39.0", "description": "Persistent Gainsight Admin CLI workspace — bootstrap, index, and operate on a Gainsight tenant via gs-admin.", "author": { "name": "BradleyDB" diff --git a/plugins/gs-superadmin/CHANGELOG.md b/plugins/gs-superadmin/CHANGELOG.md index 4bb189d..9836071 100644 --- a/plugins/gs-superadmin/CHANGELOG.md +++ b/plugins/gs-superadmin/CHANGELOG.md @@ -5,6 +5,38 @@ marketplace doesn't pin versions — users get main — so entries describe what user who updates, not internal refactors. Entries before 0.8.0 were reconstructed from git history when this file was introduced. +## 0.39.0 — 2026-09-14 + +The operating model's Role section gains *The admin's job, and yours*, and the +change-request plan gains a **Before building** section that comes from it. What a user +gets by updating: every session is told how a good CS Ops admin thinks about a change — +not just whether the tenant can build it, but what it does to the CS team's strategy, the +CSMs who'll work it, the data it depends on, and the customers on the other end — and that +its own job is to do that thinking with the KB open, ask the questions a newer admin might +not think to, and tell the admin where the build as asked doesn't fit and what the better +version costs, in as few lines as the change deserves, leaving the decision with the +admin. The plan carries that between the impact analysis and the assets, held to one test: +would the admin build or say something different after reading it? If the tenant already +has a way to do this, the section cites the KB doc and says what that way gives up; where +the ticket left something open, it says which way the plan went and asks; a ticket that +says what it's for and asks for the right thing gets one line saying so. The plan is +written on the ask as stated whatever the section says, and the chat summary's `Heads-up:` +line shows the one line the admin most needs before opening the file. + +- `templates/operating-model.md` Role: the one canonical statement; the skill points at + it. Existing workspaces pick it up through the scaffold's `.new` flow at the next setup + or refresh. +- `skills/change-request/SKILL.md` step 4 teaches the thinking and the one test for what + gets written; step 7's summary gains the `Heads-up:` line. +- `references/plan-template.md`: the section, its render rule, and its exact empty line + (`Nothing to add — the change as asked is the direct way to do it, and nothing the + ticket left out would change this plan.`). +- `test/change-request-fixtures.mjs` locks the section across the four documents that + teach, render, summarize, and ground it; the expected plan demonstrates it (the + fixture's playbook decision moves from Risk notes into the reading, where it belonged). +- Skill prose only — no script, hook, or guard behaviour moves. The tester walk is owed + (no tenant in the contributor session); see the PR. + ## 0.38.0 — 2026-09-11 Setup Phase 4's index-or-exclude decision is bound to the overlap check's numbers. What a diff --git a/plugins/gs-superadmin/README.md b/plugins/gs-superadmin/README.md index 11b4b6c..14a3ff9 100644 --- a/plugins/gs-superadmin/README.md +++ b/plugins/gs-superadmin/README.md @@ -185,12 +185,22 @@ same objects/fields), applies the workspace naming convention, and writes a revi request-event schema and ticket anatomy are vendored frozen contracts (canonical: `BradleyDB/CS_GTM_Tools`). +The plan also has a **Before building** section: what a good CS Ops admin would say about +the ticket if they had time to think it over — not just whether it can be built, but what +it does to the CS team's strategy, the CSMs who'll work it, the data it depends on, and +the customers on the other end. Where the build as asked doesn't fit, it says what would +and what that costs. Where the ticket left something open, it says which way the plan went +and asks the question, so you can confirm it in a glance or send it back to the requester. +When there's nothing to add, it says so in one line. The plan is written on the ask as +stated either way — nothing waits on you — and the chat summary shows the one line you +most need before you open the file. + The lifecycle, end to end — the key point is that **drafting is always safe**: 1. **Draft** — `/gs-superadmin:change-request ticket.md --ticket CSOPS-142` writes the plan file. Nothing is executed at drafting time, ever. -2. **Review** — open the plan, check the impact analysis, names, command sequence, and - rollback. Edit or discard freely; it's just a markdown file. +2. **Review** — open the plan, check the impact analysis, the *Before building* read, names, + command sequence, and rollback. Edit or discard freely; it's just a markdown file. 3. **Execute** — a separate, explicit ask ("execute the CSOPS-142 plan"). Commands run one at a time, each catalog-mutating command behind the approval prompt. The plan's guard-coverage section names the steps that will run without one — your approval of diff --git a/plugins/gs-superadmin/skills/change-request/SKILL.md b/plugins/gs-superadmin/skills/change-request/SKILL.md index 35ef9d2..330c0d4 100644 --- a/plugins/gs-superadmin/skills/change-request/SKILL.md +++ b/plugins/gs-superadmin/skills/change-request/SKILL.md @@ -1,5 +1,5 @@ --- -description: Turn a change request (Jira ticket with a handoff block, request-event JSON, or pasted text) into a reviewable implementation plan — KB impact analysis, convention-checked names, exact gs-admin commands, rollback. +description: Turn a change request (Jira ticket with a handoff block, request-event JSON, or pasted text) into a reviewable implementation plan — KB impact analysis, a *Before building* read, convention-checked names, exact gs-admin commands, rollback. disable-model-invocation: true argument-hint: " [--ticket KEY] [--slug name]" --- @@ -154,6 +154,36 @@ Impact questions to answer explicitly: - What consumes the outputs downstream (scorecard measures, reports, dashboards, syncs)? - Does anything scheduled need to run before/after the new or changed asset? +Then, with the KB still open, think about the change the way a good CS Ops admin would if +they had the time (operating model, Role: *The admin's job, and yours*). This becomes the +plan's *Before building* section. The impact analysis above is the list of what's touched; +this is what you make of it. Think past the tenant to the CS team it serves — the +strategy, the CSMs, the data, the customers — the way the operating model lays it out. The +KB and the CLI can tell you what's true about the tenant; only the admin or the requester +can tell you what's true about the people. Then say what a senior CS Ops person would say +before building: where the build as asked doesn't fit and what the better version costs, +plus the questions they'd ask that a newer admin might not think to. A question goes in +only if the answer would change what gets built or how it's rolled out. Wherever the ask +was silent, the plan had to pick something, and once picked it looks decided — so put each +question next to the default the plan took, and the admin can confirm it in a glance or +pass it to the requester. Match the length to the size of the change; a small change that +fits gets a line. + +If you say the tenant already has a way to do this, cite the KB doc that shows it and say +what you'd give up by going that way — if there's no cost, you haven't looked hard enough. +If the ticket doesn't say what it's for, your guess is marked as a guess: the header's +`Justification:` tag reads `AI-inferred` (template render rule). And nothing waits on an +answer: write the plan now, on the ask as stated. + +One test for every line: **can you point to the line of the plan, or the thing the admin +would say to the requester, that changes if they take this on board?** Something true +about the tenant that changes nothing is commentary, and the impact table already has it. +The wrong test is "would a thorough consultant mention this?" — with the KB open the +answer is yes to everything, and you get a memo nobody working a queue will read. If +nothing passes, the section says so in one line; a ticket that says what it's for and asks +for the right thing gets exactly that. Never try to talk the admin out of what the +business needs: build what was asked, and put the better route next to it with its cost. + ### 5 — Names, conventions, risk **Names**: load the workspace convention exactly as `/gs-superadmin:audit` step 2 does @@ -249,12 +279,15 @@ The command sequence in the plan must: ### 7 — Report and stop Summarize in chat: what the change is, impacted assets found (count + the notable ones), -proposed names, environment flag, and the plan file path. Then stop: +proposed names, environment flag, and the plan file path. Then stop. The `Heads-up:` line +is the one line from *Before building* the admin most needs to see before opening the file +— or "nothing to add": ``` ✓ change-request plan drafted — nothing has been executed - Plan: /changes/-.md - Ticket: + Plan: /changes/-.md + Ticket: + Heads-up: Review the plan, edit it if needed, then tell me explicitly to execute it. ``` diff --git a/plugins/gs-superadmin/skills/change-request/references/plan-template.md b/plugins/gs-superadmin/skills/change-request/references/plan-template.md index 62b313f..a3a2c9f 100644 --- a/plugins/gs-superadmin/skills/change-request/references/plan-template.md +++ b/plugins/gs-superadmin/skills/change-request/references/plan-template.md @@ -33,6 +33,15 @@ Render rules — read before the fence: documented assets in gs-rules; run /gs-superadmin:refresh"⟩` when none). The *Assets to create/modify* list, *Command sequence* steps, *Manual (UI-only) steps*, and *Rollback* steps likewise repeat once per item, keeping their numbering continuous. +- *Before building* holds what step 4 turned up — only what would change what the admin + builds or says to the requester, in as few lines as it takes. If it names a way the + tenant can already do this, it cites the KB doc and says what that way gives up; if it + raises a choice the plan made where the ask was silent, it says which way the plan went; + if it guesses at what the ticket is for, it says so, and the header's `Justification:` + tag reads `AI-inferred`. When nothing would change, the section is exactly `Nothing to + add — the change as asked is the direct way to do it, and nothing the ticket left out + would change this plan.` Whatever the section says, the plan is written on the ask as + stated; nothing here holds up drafting. - In the command sequence, values that can only be resolved against the live tenant at execution time stay as `⟨resolve live: what and how⟩` — that is the one placeholder form that legitimately survives into the plan file (it is resolved at execution, not at @@ -73,6 +82,10 @@ Render rules — read before the fence: ⟨freshness caveats: docs past TTL, undocumented domains, refresh recommendation — or "KB fresh for all cited assets"⟩ +## Before building + +⟨what step 4 turned up, in as few lines as it takes — only what would change what the admin builds or says to the requester — or exactly "Nothing to add — the change as asked is the direct way to do it, and nothing the ticket left out would change this plan."⟩ + ## Assets to create / modify 1. **⟨CREATE | MODIFY⟩** ⟨asset type⟩: `⟨convention-compliant name⟩` — ⟨one line: what it does⟩ diff --git a/plugins/gs-superadmin/templates/operating-model.md b/plugins/gs-superadmin/templates/operating-model.md index 51ad953..ca08657 100644 --- a/plugins/gs-superadmin/templates/operating-model.md +++ b/plugins/gs-superadmin/templates/operating-model.md @@ -9,6 +9,41 @@ - **CLI (`gs-admin`) = source of truth.** Run it for every read; never guess at API responses. - **This KB (`/`) = memory/map.** Documented assets here save re-fetching; they are inputs to reasoning, not authoritative without verification. +- **The admin = the judgment between what the business asks for and what the tenant should do.** + +### The admin's job, and yours + +A request usually shows up as a build: the person asking has already picked the Gainsight +feature they think they need, out of the ones they know about. A good CS Ops admin doesn't +just check whether it can be built. They think about what it does to the whole operation +the tenant serves — the CS team's strategy, the CSMs who'll have to work it, the data it +depends on, the customers on the other end, and the tenant it lands in. Is this what the +CS team is trying to do, or just what this person asked for? Will the CSMs do the thing, +or ignore it — and what does that teach them about the system? Is the data it reads good +enough to drive it, and does writing to a field change what that field means to everything +else that uses it? Does anything go out to customers? Could the tenant already do this, or +nearly? Who keeps it working after the requester has moved on? Should the process behind +the ask exist at all? What are we signing up for by saying yes? And how much of that +thinking does this one change deserve — a small change gets a small think. Then they say +the one or two things that matter: where the build as asked doesn't fit, and what the +better version costs. When there's time, that's a conversation with the business. When +there isn't, it gets skipped and the ticket gets built as written. And someone new to the +role hasn't had the years that make those questions automatic. + +Your job is the same job, one level down. Do that thinking for the admin, with the KB +open, and ask the questions they might not have thought to ask yet. Whenever you're asked +to change the tenant, put what you found in front of them — in the plan, or in your reply +— in as few lines as it takes, and no more than the change deserves. What you can't know +is the people and the history around the request; ask about those only when the answer +would change what gets built or how it rolls out, and don't wait for the answer — draft +the plan on the ask as stated and put the questions next to it. Two ways to get this +wrong: build the ticket as written and say nothing; or write up everything true you found +in the KB whether or not it changes anything, which nobody working a queue will read. The +test for every line: would the admin build, roll out, or say something different after +reading it? If not, leave it out. The admin decides. They're trying to give the business +what it needs; you show the best way to get there and what it costs, and you don't try to +talk them out of it. A plain question gets a plain answer — plus the one thing they'd want +to know, if the answer turns one up. --- diff --git a/plugins/gs-superadmin/test/change-request-fixtures.mjs b/plugins/gs-superadmin/test/change-request-fixtures.mjs index 099e8da..e5f0594 100644 --- a/plugins/gs-superadmin/test/change-request-fixtures.mjs +++ b/plugins/gs-superadmin/test/change-request-fixtures.mjs @@ -218,6 +218,28 @@ check("operating model states the set-source fact with the same terms as SKILL.m operatingModel.includes('"Select an Object"') && skillDoc.includes('"Select an Object"') && operatingModel.includes("set-source-template") && operatingModel.includes("Prepare Dataset"), null); +// 6b — the admin's reading (plugin 0.39.0): the plan's Before-building section is +// taught in SKILL.md step 4, rendered by the template with its honest empty line, +// surfaced in the step-7 chat summary, and grounded in the operating model's Role +// section — all four load into the same session, so the section must exist in every +// one of them or the LLM drafts it from whichever copy it read last. +const EMPTY_READ = "Nothing to add — the change as asked is the direct way to do it, and nothing the ticket left out would change this plan."; +check("plan template carries the Before building section and its honest empty line", + planTemplate.includes("## Before building") && planTemplate.includes(EMPTY_READ), null); +check("plan template ties a guessed purpose to the header's AI-inferred tag", + planTemplate.includes("`AI-inferred`"), null); +check("SKILL.md step 4 teaches the one test for what the reading writes", + skillDoc.includes("*Before building*") && + skillDoc.includes("can you point to the line of the plan, or the thing") && + skillDoc.includes('"would a thorough consultant mention this?"'), null); +check("SKILL.md step-7 summary fence carries the Heads-up line", + /```\n✓ change-request plan drafted[\s\S]*?\n Heads-up: <[\s\S]*?```/.test(skillDoc), null); +check("operating model Role carries the admin's job and the session's", + operatingModel.includes("### The admin's job, and yours") && + operatingModel.includes("Your job is the same job, one level down."), null); +check("expected plan demonstrates the Before building section", + expectedPlan.includes("## Before building") && !expectedPlan.includes(EMPTY_READ), null); + // 7 — journal outcome wording: the operating model quotes the hook's outcome // strings verbatim; lock doc and hook together so a rewording in either file // fails here instead of stranding the other. diff --git a/plugins/gs-superadmin/test/fixtures/change-request/expected-plan.md b/plugins/gs-superadmin/test/fixtures/change-request/expected-plan.md index e516004..a502344 100644 --- a/plugins/gs-superadmin/test/fixtures/change-request/expected-plan.md +++ b/plugins/gs-superadmin/test/fixtures/change-request/expected-plan.md @@ -40,6 +40,31 @@ KB fresh for all cited assets (last refresh 2026-06-28, within TTL). Field names `NPS_Score__gc` / `Segment__gc` are KB-confirmed but must be re-verified live at execution time (step 1 below) since this plan was drafted without CLI access. +## Before building + +- `NPS_Score__gc` is each company's latest survey response, however old + (`rules-engine/rul-9f3e21.md` loads the most recent response every night, with its date + in `NPS_Response_Date__gc`). So as written, the rule opens a CTA today for a detractor + score from any past survey — and, since the score is still below 6 after the CSM closes + the CTA, opens it again the next morning. A CSM who closes the same alert three mornings + running stops reading alerts. The plan builds what was asked (any current score below + 6); if a detractor has to be recent to count, step 6 gets a fourth condition on + `NPS_Response_Date__gc`, and the requester should say how recent. +- The ticket says what it's for and asks for a rule of its own; this plan builds that. The + tenant already has a Risk CTA rule on these companies — `CTA|DRIVE|CSM Low Health Score + Risk Alert` (`rules-engine/rul-4b7d10.md`) — and the NPS check could go in there as a + second action with its own reason: one rule, one schedule. The downside: you'd be + editing a rule that's already opening CTAs in production, you couldn't test or roll back + the NPS piece on its own, and the NPS alert would run on that rule's 05:00 UTC schedule. +- Either way, Enterprise CSMs get a second stream of Risk CTAs: an account whose NPS drops + can end up with two open Risk CTAs for one problem, one for health and one for NPS. The + requester should expect that, or say which one should win. +- Two choices the ticket left to the plan: no playbook attached (attaching the existing + "Risk Mitigation" playbook changes step 7's action flags and the due date from +5 to +0 + days; a Risk CTA with nothing to do attached is the kind CSMs close without reading), + and "Enterprise" read as the `Segment__gc` picklist value alone (an ARR threshold adds a + condition in step 6 and a field to verify). + ## Assets to create / modify 1. **CREATE** Rules Engine rule: `CTA|DRIVE|CSM Enterprise NPS Below 6 Risk Alert` — opens a @@ -68,9 +93,6 @@ time (step 1 below) since this plan was drafted without CLI access. `executions`) are catalog-non-mutating and pass silently. Those prompts confirm each command; explicit user approval of this plan is the gate. Commands are run one at a time, only after that approval, only from this list. -- **Open decision for the reviewer:** attach the existing "Risk Mitigation" playbook (then - due date +0 days per convention) or run playbook-less with the default +5-day due date? - The request doesn't say; the plan assumes **no playbook** until the reviewer decides. ## Command sequence