-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add reportcard skill #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 4 commits
ab5adaa
4154b57
ea2baa0
69c072b
25f75be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # Product skills | ||
|
|
||
| Product management workflows. No per-repo setup required — available immediately after installing the plugin. | ||
|
|
||
| These skills operate on a product's own repository (for example the products.open.gov.sg content repo), so run them from that checkout rather than from here. | ||
|
|
||
| ## Skills | ||
|
|
||
| | Skill | Description | | ||
| |-------|-------------| | ||
| | [`/reportcard`](reportcard/SKILL.md) | Add a quarter's team, cost and metric values to an OGP product report card by auditing the last recorded quarter, then asking the PM for each missing number | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| # Ask format | ||
|
|
||
| How to present the audit to a PM and collect their numbers. | ||
|
|
||
| ## Output order | ||
|
|
||
| **Tables first, prose last.** Four tables back to back, one-line captions | ||
| only, then a single Notes block, then the reply block. Never interleave | ||
| commentary between tables — it breaks the scan, and the tables are what the | ||
| PM is actually reading. | ||
|
|
||
| 1. One-line header — product and target quarter | ||
| 2. **Team** table | ||
| 3. **Cost** table | ||
| 4. **Metrics** table | ||
| 5. **Dormant** table (omit if empty) | ||
| 6. **Notes** (omit if nothing to flag) | ||
| 7. **Reply block** | ||
|
|
||
| Order rows the way `reportcard.yml` orders them — `team`, then `cost` keys, | ||
| then metrics in `metricGroups` order, then `changelog`. The audit already | ||
| prints them in file order, so the PM can read the file and the ask in step. | ||
|
|
||
| ## Tables | ||
|
|
||
| Every table shows the previous quarter filled and the target quarter blank. | ||
| Use **quarter labels as headers, never ISO dates**. The audit prints the exact | ||
| pair as `table columns:` — copy it rather than deriving it. | ||
|
|
||
| Team: | ||
|
|
||
| | Person | Role | Q1 2026 | Q2 2026 | | ||
| | --- | --- | --- | --- | | ||
| | alex | eng | full | | | ||
| | bo | ops | 2/3 | | | ||
|
|
||
| Quarter columns hold involvement (`full` when the YAML omits `involvement`). | ||
| Blank means carry forward; `-` means the person left. Caption with the quarter | ||
| the roster came from, and ask only for the **delta** — "unchanged" is a valid | ||
| and common answer. Never render a roster as a prose sentence; it is the | ||
| hardest bucket to check by eye. | ||
|
|
||
| Cost and Metrics: | ||
|
|
||
| | id | Q1 2026 | Q2 2026 | | ||
| | --- | --- | --- | | ||
| | infra | 12,345.67 | | | ||
| | paper-forms-left | 12,000 | | | ||
| | cost-per-form-submission-manual | $0.25 | | | ||
|
|
||
| Dormant uses `id` + `Last value` + `Quarters missing` — **no target-quarter | ||
| column**, since nothing is being collected. Caption it as awareness only, e.g. | ||
| "not collected — say the word to revive". It is a record that these once | ||
| existed, not a request. | ||
|
|
||
| ### Formatting values | ||
|
|
||
| - Thousands separators and prefixes are for readability only. Write the raw | ||
| number into the YAML. | ||
| - Take a prefix **verbatim from the metric's own `prefix` field**. A metric | ||
| with `prefix: '$'` renders as `$0.25`, never `FormSG$0.25`. The product name | ||
| belongs in the header line and nowhere else. | ||
| - Use each id exactly as it appears in the file, including odd casing like | ||
| `Uptime`. | ||
|
|
||
| ## Notes | ||
|
|
||
| One bullet per flag, only things that change what the PM should do: | ||
|
|
||
| - Roster empty, or carried forward from more than one quarter back | ||
| - Cost fields at `0` — real, or a placeholder? `0` renders as a genuine | ||
| datapoint on the public chart | ||
| - **Cost gates the whole quarter.** The quarter dropdown is built from | ||
| `cost.values` alone, so until a cost entry exists the new quarter will not | ||
| appear on the page at all. Say so when asking, so the PM knows these six | ||
| numbers unblock everything else | ||
| - `CHANGELOG.md` missing intervening quarters | ||
| - Dormant metrics — one bullet total, not one per metric | ||
|
|
||
| Nothing to flag means no Notes block. Do not pad it. | ||
|
|
||
| ## Reply block | ||
|
|
||
| A PM gathers these numbers from finance, Datadog, and a survey, so they will | ||
| answer in pieces. Always end with a copy-paste block keyed by id, in file | ||
| order: | ||
|
|
||
| ``` | ||
| team: unchanged | ||
| infra: 0 | ||
| security: 0 | ||
| manpower: 0 | ||
| corporate: 0 | ||
| tools: 0 | ||
| others: 0 | ||
| paper-forms-left: | ||
| cost-per-form-submission-manual: | ||
| respondent-satisfaction-rating: | ||
| admin-satisfaction-rating: | ||
| Uptime: | ||
| paper-forms-left-moe-schools: | ||
| percentage-forms-converted-schools: | ||
| changelog: | ||
| ``` | ||
|
|
||
| The `changelog:` line is optional and exists only so a PM who already has the | ||
| text can hand it over. Leaving it blank is normal — `/highlights` writes a | ||
| proper entry from a scan of Slack, GitHub and the planning doc. Never write | ||
| one yourself from the metric values. | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 25f75be — same fix, dropped the /highlights reference. |
||
|
|
||
| **Cost keys are pre-filled with `0`** — not because zero is likely right, but | ||
| because a quarter with no cost entry does not render at all. The default gets | ||
| the PM to a previewable page without waiting on finance. | ||
|
|
||
| Say this when you send the block: *"cost is pre-filled with 0 so the quarter | ||
| renders — overwrite with real figures when finance sends them."* | ||
|
|
||
| Treat cost as unanswered whenever **all six come back as `0`**. That is the | ||
| default echoed back, not a decision, so it means placeholder: draft PR, flagged | ||
| in the description. Individual zeros are ordinary — most products genuinely | ||
| have `security: 0` — so only the all-zero case is the signal. | ||
|
|
||
| **Only `NEED` items appear here.** Never put a dormant metric in the reply | ||
| block, not even commented out — a blank line reads as an obligation, and the | ||
| whole point of dormant is that the PM owes nothing. Reviving one is opt-in: | ||
| they name it explicitly ("bring back officer-satisfaction"), and only then | ||
| does it join the block on the next round. | ||
|
|
||
| - **Partial is fine.** A blank line is unanswered. Re-ask only the blanks; | ||
| never re-ask what is already filled. | ||
| - **Order-independent and unambiguous** — keys are ids, so nothing misaligns | ||
| the way a bare list of numbers does. | ||
| - Loose replies are fine too (`total-users 12500`, or one value at a time). | ||
| The block is a convenience, not a required format. | ||
|
|
||
| Keep asking in rounds until every line is filled or the PM stops, then write | ||
| `TBC` for the rest and list them at the end. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| --- | ||
| name: reportcard | ||
| description: Add a new quarter's team, cost and metric values to an OGP product report card (_products/<product>/reportcard.yml) by auditing the last recorded quarter, then asking the PM for each missing number. Use when someone wants to update, add, or draft a quarterly report card, add a new quarter's metrics/cost/team, or mentions reportcard.yml, "Q1/Q2/Q3/Q4 report card", or the products.open.gov.sg draft editor. For writing the CHANGELOG entry, use the highlights skill instead. | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 25f75be — removed the reference to the not-yet-existing /highlights skill; the description now just says CHANGELOG writing is out of scope for this skill. |
||
| --- | ||
|
|
||
| # Report card: add a quarter | ||
|
|
||
| Collect a quarter's numbers from the PM and append them to | ||
| `_products/<product>/reportcard.yml`. | ||
|
|
||
| Does not source data, does not open PRs, and does not write the changelog — | ||
| `/highlights` owns that, and will be suggested if the quarter has no entry. **Never invent, interpolate, or | ||
| carry forward a metric value** — every number comes from the PM, anything | ||
| unanswered stays `TBC`, and past quarters are never edited. | ||
|
|
||
| ## 1. Audit — never read the YAML by eye | ||
|
|
||
| ```bash | ||
| python3 scripts/audit.py _products/<product>/reportcard.yml | ||
| ``` | ||
|
|
||
| Stdlib only, so it runs before `npm i`. `--quarter 2026-04-01` targets a | ||
| specific quarter; otherwise it infers the next one. `--active-only` hides | ||
| retired metrics. | ||
|
|
||
| It prints the target quarter, the table headers to use, the branch name and | ||
| its status, the last roster and cost entry, and sorts every metric into: | ||
|
|
||
| | Bucket | Meaning | What to do | | ||
| | --- | --- | --- | | ||
| | `NEED` | Carried a value last quarter | Ask the PM | | ||
| | `auto` | Derived from other fields | Never ask | | ||
| | `DORMANT` | No value last quarter | Offer once, then drop | | ||
|
|
||
| PMs retire metrics all the time, so a quiet metric is usually a deliberate | ||
| choice rather than an oversight. Offer the dormant list once so nothing is | ||
| lost silently, accept "skip them", and never raise it again. | ||
|
|
||
| Heed the cost warning if it appears — a quarter without a `cost.values` entry | ||
| does not render at all. | ||
|
|
||
| ## 2. Ask | ||
|
|
||
| Follow [ASK-FORMAT.md](ASK-FORMAT.md): four tables, then Notes, then a | ||
| copy-paste reply block keyed by metric id in file order. Show every last-known | ||
| value so the PM can answer with a delta rather than hunting for context. | ||
|
|
||
| ## 3. Write | ||
|
|
||
| Follow [WRITING.md](WRITING.md): branch at the first write, append-only edits, | ||
| and what to do when the cost figures have not arrived. | ||
|
|
||
| ## 4. Verify | ||
|
|
||
| ```bash | ||
| git diff _products/<product>/reportcard.yml | ||
| ``` | ||
|
|
||
| **Every hunk must be pure additions.** One deleted line means history was | ||
| rewritten instead of appended — stop and fix it. Re-run the audit; every | ||
| `NEED` should now read `OK`. | ||
|
|
||
| Then have the PM preview at `products.open.gov.sg/draft/<product>` before the | ||
| PR. The diff catches structural damage; only the preview catches a plausible | ||
| number in the wrong row. | ||
|
|
||
| Handing off for review is `prepare-for-review`'s job, not this skill's. Any | ||
| screenshot goes in `.scratch/` and is never committed. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| # Writing the draft | ||
|
|
||
| ## Branch — created at the first write, not at launch | ||
|
|
||
| The audit prints the conventional name as `branch:` | ||
| (`<product>-q<n>-<year>-report-card`). Running this skill is not a commitment | ||
| to change anything, so a read-only question must not leave a branch behind. | ||
|
|
||
| Create it immediately before the first write. If the PM replies and nothing | ||
| gets written ("hold off", or every answer is "skip"), no branch. A partial | ||
| draft containing `TBC` is a write, so it does get one. | ||
|
|
||
| ```bash | ||
| git switch -c <branch> # only if it does not already exist | ||
| ``` | ||
|
|
||
| Already on that branch, or on a non-`main` branch the PM is clearly using? | ||
| Stay there. Otherwise act on what the audit reported: | ||
|
|
||
| | Audit says | Do | | ||
| | --- | --- | | ||
| | `exists locally` | Switch to it, keep going | | ||
| | `exists on REMOTE only` | **Stop and ask.** Someone else likely started this quarter | | ||
| | `not found` | Create it here | | ||
| | `git unavailable` | Carry on, and say the branch step was skipped | | ||
|
|
||
| ## Appending | ||
|
|
||
| New entry keyed by `startDate: 'YYYY-MM-01'`, month `01`/`04`/`07`/`10`. | ||
|
|
||
| - Match surrounding style exactly — indentation, date quoting, decimal places. | ||
| - `team.members`: omit the block entirely to carry the roster forward. Add one | ||
| only if it actually changed. | ||
| - `cost.values`: all six keys — `infra`, `security`, `manpower`, `corporate`, | ||
| `tools`, `others`. | ||
| - `CHANGELOG.md`: **not this skill's job** — `/highlights` owns it, because a | ||
| good entry needs a scan of Slack, GitHub and the team's planning doc. | ||
| - If the PM supplies changelog text directly, add it at the top as | ||
| `## Q<n> <year> <Mon-Mon>`, matching the previous entry's structure. | ||
| - If they do not, leave the file alone and say the quarter is missing an | ||
| entry, then point them at `/highlights`. Do not improvise one from the | ||
| metric values — numbers are not a story. | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 25f75be — reworded to drop the /highlights reference and just note this is out of scope for the skill. |
||
|
|
||
| ## When the cost figures are not in yet | ||
|
|
||
| **A quarter exists only if it has a `cost.values` entry.** The quarter | ||
| dropdown is built from `cost.values` keys alone | ||
| (`src/app/services/calculate-costs.ts`); metrics do not contribute. Add | ||
| metrics without a cost entry and the page silently keeps showing the previous | ||
| quarter — no error, nothing to notice. | ||
|
|
||
| So cost blocks *preview*, never *progress*: | ||
|
|
||
| 1. Write the metrics as normal. | ||
| 2. Add the cost entry with zeros so the quarter renders, and say plainly that | ||
| you have done so. | ||
| 3. Open the PR as a **draft**, with `cost figures are placeholder zeros` in | ||
| the description as the one outstanding item. | ||
|
|
||
| A draft carrying zeros is normal — it is what makes the quarter previewable. | ||
| **Approval is the gate:** reviewers do not approve until the real figures land | ||
| in a follow-up commit. | ||
|
|
||
| The danger is silence, not the zeros. On the public chart a `0` reads as | ||
| "spending collapsed to nothing" rather than "not known yet", so an unflagged | ||
| draft can be approved by someone assuming the numbers are real. | ||
Uh oh!
There was an error while loading. Please reload this page.