rpa-bot-handoff: one 54-line SKILL.md, no reference or template files
The skill is now one SKILL.md (54 lines) with the SOP shape inline, plus templates/to_docx.py for the Word and PDF. Removed: the template, the MEK reference example and the skill README. The converter's selfcheck uses a built-in sample. Tests now check the skill is that one short file, has the 6 don't-miss checks, and its SOP shape has the 5 sections and To/CC lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
36e621b153
commit
b35796e1a5
8 files changed
+89
-247
No files matched your search
+1
-1
@@ -37,7 +37,7 @@ It is hidden for bots that take no input file.
|
|||||||
|
|
||||||
**Fake bot**: a bundled script that prints the Run tab protocol lines, used to verify the page. The skill never runs the real bot.
|
**Fake bot**: a bundled script that prints the Run tab protocol lines, used to verify the page. The skill never runs the real bot.
|
||||||
|
|
||||||
**Handover SOP**: the `<Project Name> Handover SOP` the `rpa-bot-handoff` skill writes in a bot's repo (`HANDOVER-SOP.md` plus a Word copy), for the operator who runs the bot and does not read code. At most 4 pages, 5 sections in the operator's order: how to run, what you see while it runs, result, when something goes wrong, email us. See ADR-0005. _Avoid_: "ops guide" (the old 11-section format).
|
**Handover SOP**: the `<Project Name> Handover SOP` the `rpa-bot-handoff` skill writes in a bot's repo (`HANDOVER-SOP.md` plus Word and PDF copies; ops get the PDF), for the operator who runs the bot and does not read code. At most 4 pages, 5 sections in the operator's order: how to run, what you see while it runs, result, when something goes wrong, email us. See ADR-0005. _Avoid_: "ops guide" (the old 11-section format).
|
||||||
|
|
||||||
|
|
||||||
**Exception list**: the table in section 4 of the Handover SOP: one numbered row (`E01`...) per message the operator can see, with what it means and what to do, including when to email the dev team.
|
**Exception list**: the table in section 4 of the Handover SOP: one numbered row (`E01`...) per message the operator can see, with what it means and what to do, including when to email the dev team.
|
||||||
|
|||||||
@@ -11,3 +11,5 @@ Supersedes ADR-0004.
|
|||||||
**Kept from ADR-0004:** the operator's words only, every wait is a number from the code, misleading statuses are called out where they show, the bot is never run, and the bot is checked for every common problem type.
|
**Kept from ADR-0004:** the operator's words only, every wait is a number from the code, misleading statuses are called out where they show, the bot is never run, and the bot is checked for every common problem type.
|
||||||
|
|
||||||
**Shorter skill (Oct 2026):** the user found the skill itself too detailed. SKILL.md is now a short checklist (under 500 words), the 12 Tebra failure classes are folded into 6 one-line "don't miss" checks, and the MEK Charge Reconciliation SOP (the 3-page PDF ops liked) replaces the Tebra example as the model.
|
**Shorter skill (Oct 2026):** the user found the skill itself too detailed. SKILL.md is now a short checklist (under 500 words), the 12 Tebra failure classes are folded into 6 one-line "don't miss" checks, and the MEK Charge Reconciliation SOP (the 3-page PDF ops liked) replaces the Tebra example as the model.
|
||||||
|
|
||||||
|
**One file (Oct 2026):** the user asked for about 50 lines. The skill is now one `SKILL.md` (under 60 lines) with the SOP shape inline, plus `templates/to_docx.py` for the Word and PDF. The template, the reference example and the README are removed.
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# rpa-bot-handoff
|
|
||||||
|
|
||||||
A Claude skill that writes a short **Handover SOP** for an RPA bot that is being handed over to an ops team.
|
|
||||||
|
|
||||||
## What you get
|
|
||||||
**`<Project Name> Handover SOP.pdf`** (plus the `.docx` and `HANDOVER-SOP.md`): at most 4 pages, in plain words, for operators who don't read code:
|
|
||||||
1. How to run: the URL or shortcut, what to click, and what a new click does to the previous results
|
|
||||||
2. What you see while it runs: what shows where, a normal run, how long each step may take
|
|
||||||
3. Result: how a good run ends, where the report is, what each status means
|
|
||||||
4. When something goes wrong: how it shows, each message (E01, E02...) with what to do, the don'ts, how to stop it
|
|
||||||
5. Email us: To the developer, CC their manager, when to email, and the email to copy
|
|
||||||
|
|
||||||
Problems the scan finds for the dev team are listed in the chat, not in the SOP.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
Copy this folder to `~/.claude/skills/rpa-bot-handoff/`.
|
|
||||||
|
|
||||||
## Use
|
|
||||||
In your bot project, ask Claude: *"write the handover SOP for this bot"* or *"document this bot for handover"*. The skill:
|
|
||||||
1. Scans the code with a subagent. It never runs the bot.
|
|
||||||
2. Asks up to two things: the developer's and the manager's email (To and CC), and where ops runs the bot.
|
|
||||||
3. Writes the SOP, checks every quoted message and label against the code, and keeps it under 1,400 words.
|
|
||||||
4. Turns it into Word and PDF; you give the PDF to ops.
|
|
||||||
|
|
||||||
## Files
|
|
||||||
| File | What it is |
|
|
||||||
|---|---|
|
|
||||||
| `SKILL.md` | Steps Claude follows |
|
|
||||||
| `templates/HANDOVER-SOP.md` | The SOP skeleton |
|
|
||||||
| `templates/reference/mek-charge-reconciliation.md` | The model SOP (MEK Charge Reconciliation, 3 pages) |
|
|
||||||
| `templates/to_docx.py` | Turns the SOP into Word, and with `--pdf` into PDF; prints word and page counts (`--selfcheck` tests it) |
|
|
||||||
@@ -5,27 +5,47 @@ description: Writes "<Project Name> Handover SOP" - a short PDF (at most 4 pages
|
|||||||
|
|
||||||
# RPA bot handoff
|
# RPA bot handoff
|
||||||
|
|
||||||
Make **`<Project Name> Handover SOP`**: one PDF, at most 4 pages, that ops keeps open while they run the bot. `templates/reference/mek-charge-reconciliation.md` is the model: copy its length, layout and tone.
|
Make **`<Project Name> Handover SOP`**: one PDF, at most 4 pages, that ops keeps open while they run the bot. Plain words, no code.
|
||||||
|
|
||||||
## Steps
|
1. **Scan.** One read-only subagent (never run the bot; no patient data, client names or passwords in its report). Ask for exact on-screen text with file:line: how to start (URL or shortcut, sign-in, Run button, what a new run does to old results), what shows where during a run, every timeout and retry, how a run ends and where the result is, every message ops can see, alerts, how to stop.
|
||||||
|
2. **Ask once:** the developer's email (To), the manager's name and email (CC), and where ops runs it if unclear.
|
||||||
|
3. **Write** `HANDOVER-SOP.md` in this shape:
|
||||||
|
|
||||||
1. **Scan.** Start one read-only subagent: never run the bot, no patient data, client names or passwords in its report. Ask for exact on-screen text with file:line: how to start (URL or shortcut, sign-in, Run button, what a new run does to old results), what shows where during a run, every timeout and retry, how a run ends and where the result is, every message the operator can see, alerts, and how to stop.
|
```markdown
|
||||||
2. **Ask once:** the developer's email (To), the manager's name and email (CC), and where ops runs it if the code allows more than one place.
|
# <Project Name> Handover SOP
|
||||||
3. **Write** `HANDOVER-SOP.md` from `templates/HANDOVER-SOP.md`: 1. How to run, 2. What you see while it runs, 3. Result, 4. When something goes wrong, 5. Email us.
|
Version <x> · <date> · Problems: email <developer>, CC <manager> (section 5)
|
||||||
4. **Build** with `templates/to_docx.py`: `python <skill>/templates/to_docx.py HANDOVER-SOP.md -o "<Project Name> Handover SOP.docx" --pdf`. Over 4 pages: shorten cells, never drop a message.
|
<one line: what the bot does, from which app, what it produces>
|
||||||
5. **Hand over** the PDF. List problems for the dev team in at most 5 lines in the chat, not in the SOP.
|
## 1. How to run
|
||||||
|
Numbered steps: URL or shortcut, sign in, the Run button. Then "Before you click": what a new run does to the old results; one run at a time.
|
||||||
|
## 2. What you see while it runs
|
||||||
|
| Where on the screen | What it shows | then a normal run in one line
|
||||||
|
| Step | The bot waits at most | Then | then "Step in only when: ..."
|
||||||
|
## 3. Result
|
||||||
|
Good run / Needs a look (call out a misleading "Finished" or green). Where the result is.
|
||||||
|
| Status | Meaning | What you do |
|
||||||
|
## 4. When something goes wrong
|
||||||
|
How it shows (colour, list, column). Then:
|
||||||
|
| ID | Message you see | What it means | What you do | E01, E02 ... one row per message
|
||||||
|
Don't: (at most 3, with a short reason). To stop it: (the one right way).
|
||||||
|
## 5. Email us
|
||||||
|
Email <developer> with <manager name> (<manager email>) in CC when section 4 says "email us". Answer: <time>.
|
||||||
|
To: <developer>
|
||||||
|
CC: <manager>
|
||||||
|
Subject: <Project Name> - E<number> - <date>
|
||||||
|
Run started / Error: E<number> - <message> / Where / What I did / Attached: screenshot
|
||||||
|
Never send: passwords, patient data, result files that hold patient data.
|
||||||
|
```
|
||||||
|
|
||||||
## Rules
|
4. **Build:** `python <skill>/templates/to_docx.py HANDOVER-SOP.md -o "<Project Name> Handover SOP.docx" --pdf`. Over 4 pages: shorten cells, never drop a message.
|
||||||
|
5. **Hand over** the PDF. Problems for the dev team go in the chat (at most 5 lines), not in the SOP.
|
||||||
|
|
||||||
- Copy every label and message exactly from the code. Variable parts go in *italics*: "Couldn't download *Location*".
|
**Rules**
|
||||||
- Every wait is a number. Say plainly when the screen misleads ("Finished" while something failed).
|
- Copy every label and message exactly from the code; variable parts in *italics* ("Couldn't download *Location*").
|
||||||
- Say what clicking Run again does to the old results.
|
- Every wait is a number. Say plainly when the screen misleads.
|
||||||
- One row per message, one short line per cell.
|
- One row per message, one short line per cell.
|
||||||
- No file names, code, settings names, patient data, client names or passwords.
|
- No file names, code, settings names, patient data, client names or passwords.
|
||||||
|
|
||||||
## Don't miss
|
**Don't miss:** check each of these and cover every one that applies in section 3 or 4:
|
||||||
|
|
||||||
Check the bot for each of these, and cover every one that applies in section 3 or 4:
|
|
||||||
1. Setup missing: login, file, driver. Which message shows?
|
1. Setup missing: login, file, driver. Which message shows?
|
||||||
2. The app or portal is slow or changed: timeouts, "not found".
|
2. The app or portal is slow or changed: timeouts, "not found".
|
||||||
3. Names in the input or mapping don't match the target app.
|
3. Names in the input or mapping don't match the target app.
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
# {{PROJECT_NAME}} Handover SOP
|
|
||||||
|
|
||||||
Version {{VERSION}} · {{DATE}} · Problems: email {{DEV_EMAIL}}, CC {{MANAGER_EMAIL}} (section 5)
|
|
||||||
|
|
||||||
{{ONE_LINE: what the bot does, from which app or portal, and what it produces}}
|
|
||||||
|
|
||||||
## 1. How to run
|
|
||||||
|
|
||||||
1. {{e.g. Open https://... in Chrome / Open "<app>" from the Desktop.}}
|
|
||||||
2. {{e.g. Sign in with the team password.}}
|
|
||||||
3. {{e.g. Click "Run".}}
|
|
||||||
4. {{e.g. Wait until the status says "Finished" or "Stopped" (section 2).}}
|
|
||||||
|
|
||||||
**Before you click {{RUN_LABEL}}:**
|
|
||||||
- {{WHAT A NEW CLICK DOES: e.g. "Every click starts a fresh run on today's data. It deletes the previous run's reports first, so download them before you click."}}
|
|
||||||
- {{e.g. "Only one run at a time. A greyed-out button means a run is going."}}
|
|
||||||
|
|
||||||
## 2. What you see while it runs
|
|
||||||
|
|
||||||
| Where on the screen | What it shows |
|
|
||||||
|---|---|
|
|
||||||
| {{AREA, exact label}} | {{TEXTS IT SHOWS, in order}} |
|
|
||||||
|
|
||||||
**A normal run:**
|
|
||||||
1. {{e.g. Both lanes say "Signing in…".}}
|
|
||||||
2. {{e.g. Each lane fills: "3 of 10 locations".}}
|
|
||||||
3. {{e.g. Status "Finished", last line "Finished. Your reports are ready to download below."}}
|
|
||||||
|
|
||||||
| Step | The bot waits at most | Then |
|
|
||||||
|---|---|---|
|
|
||||||
| {{STEP}} | {{e.g. 3 min}} | {{e.g. skips that location / stops / retries 3 times}} |
|
|
||||||
|
|
||||||
**Step in only when:** {{e.g. the run has ended, or nothing new has appeared for 10 minutes}}.
|
|
||||||
|
|
||||||
## 3. Result
|
|
||||||
|
|
||||||
- **Good run:** {{HOW IT ENDS ON SCREEN}}
|
|
||||||
- **Needs a look:** {{HOW IT ENDS, including any misleading green or "Finished"}}
|
|
||||||
|
|
||||||
**Where:** {{e.g. Reports box → Download. Excel: Summary sheet, Reconciliation sheet, Result column.}}
|
|
||||||
|
|
||||||
| Status | Meaning | What you do |
|
|
||||||
|---|---|---|
|
|
||||||
| {{STATUS}} | {{ONE LINE}} | {{ACTION or "nothing"}} |
|
|
||||||
|
|
||||||
## 4. When something goes wrong
|
|
||||||
|
|
||||||
**How it shows:** {{e.g. a red or orange dot in the activity list under the Run button; the lane turns red}}.
|
|
||||||
|
|
||||||
| ID | Message you see | What it means | What you do |
|
|
||||||
|---|---|---|---|
|
|
||||||
| E01 | {{EXACT MESSAGE}} | {{ONE LINE}} | {{STEPS. "Email us" when ops can't fix it}} |
|
|
||||||
|
|
||||||
**Don't:**
|
|
||||||
- {{DON'T + short reason}}
|
|
||||||
|
|
||||||
**To stop it:** {{THE ONE RIGHT WAY}}
|
|
||||||
|
|
||||||
## 5. Email us
|
|
||||||
|
|
||||||
Email **{{DEV_EMAIL}}** with **{{MANAGER_NAME}}** ({{MANAGER_EMAIL}}) in CC when section 4 says "email us", or when the same error comes back after one re-run. Answer: {{RESPONSE_TIME}}.
|
|
||||||
|
|
||||||
```
|
|
||||||
To: {{DEV_EMAIL}}
|
|
||||||
CC: {{MANAGER_EMAIL}}
|
|
||||||
Subject: {{PROJECT_NAME}} - E<number> - <date>
|
|
||||||
|
|
||||||
Run started: <time from the screen>
|
|
||||||
Error: E<number> - <the message, copied>
|
|
||||||
Where: <location / item>
|
|
||||||
What I did: <e.g. ran it again once>
|
|
||||||
Attached: screenshot of the screen
|
|
||||||
```
|
|
||||||
|
|
||||||
**Never send:** passwords, {{SENSITIVE: e.g. the Excel reports (they hold patient names)}}.
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
# Model SOP: MEK Charge Reconciliation
|
|
||||||
|
|
||||||
The SOP ops liked: 3 pages, plain words, every message copied from the app. The email addresses are examples. Copy its length, layout and tone, not its content.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# MEK Charge Reconciliation Handover SOP
|
|
||||||
|
|
||||||
Version 0.1.0 · 28 Oct 2026 · Problems: email dev@example.com, CC manager@example.com (section 5)
|
|
||||||
|
|
||||||
Downloads the Waystar claims and the Aquilaehr visits for every MEK location, both portals at the same time, matches them by patient name and date of service, and builds one Excel report per location plus one for All Locations.
|
|
||||||
|
|
||||||
## 1. How to run
|
|
||||||
|
|
||||||
1. Open https://mek-charge-reconciliation.app.ecareindia.com/ in your browser.
|
|
||||||
2. Type the team password in **Password** and click **Sign in**. You stay signed in for 12 hours.
|
|
||||||
3. Click **Run reconciliation**.
|
|
||||||
4. Wait until the status next to the button says **Finished** or **Stopped**. Closing the tab doesn't stop the run.
|
|
||||||
|
|
||||||
**Before you click Run reconciliation:**
|
|
||||||
- **Download the reports you still need.** Every click first deletes all the previous reports, then downloads fresh data from both portals and builds new reports from it.
|
|
||||||
- Only one run at a time. If the button is greyed out and the status says "Running…", a run is already going: wait for it.
|
|
||||||
|
|
||||||
## 2. What you see while it runs
|
|
||||||
|
|
||||||
| Where on the screen | What it shows |
|
|
||||||
|---|---|
|
|
||||||
| **Waystar** and **Aquilaehr** lanes | "Ready" → "Signing in…" → "3 of 10 locations" → "All 10 downloaded" (green). Orange "8 of 10 · 2 failed" when some locations failed. Red "Stopped" when that portal stopped |
|
|
||||||
| **Excel reports** box | "Waiting for both downloads" → "Building 4 of 11" → "11 reports ready" (green) |
|
|
||||||
| Status next to the button | "Running…" → "Finished *time*" (green) or "Stopped *time*" (red) |
|
|
||||||
| Activity list under the button | One line per step, starting with "Run started *time*". Dot colours: green done, orange check this, red failed, grey progress |
|
|
||||||
| **Technical log** (click to open) | Raw lines, only for an email to us |
|
|
||||||
| **Reports** box | One row per report with "Updated *time* · *size* KB" and **Download**, plus **Download all (ZIP)** |
|
|
||||||
|
|
||||||
The page refreshes itself every 2 seconds.
|
|
||||||
|
|
||||||
**A normal run:** both lanes sign in and fill up at the same time; when both say "All 10 downloaded", the Excel box counts to "11 reports ready" and the last line says "Finished. Your reports are ready to download below."
|
|
||||||
|
|
||||||
| Step | The bot waits at most | Then |
|
|
||||||
|---|---|---|
|
|
||||||
| Sign in to each portal | 3 min | That portal stops for this run (E01) |
|
|
||||||
| Each step for one location (find, switch, load, download) | 15 s to 2 min | Skips that location. No step is retried |
|
|
||||||
|
|
||||||
**Step in only when:** the status says Finished or Stopped, or no new line has appeared in the activity list for 10 minutes (E10).
|
|
||||||
|
|
||||||
## 3. Result
|
|
||||||
|
|
||||||
- **Good run:** "Finished", both lanes green "All 10 downloaded", "11 reports ready", no red or orange dots.
|
|
||||||
- **Needs a look:** any red or orange dot, an orange or red lane, or "Stopped". **"Finished" also shows when one portal failed to sign in: always check both lanes.**
|
|
||||||
- There is no email or alert. Open the page after every run.
|
|
||||||
|
|
||||||
**Where:** **Reports** box → **Download**, or **Download all (ZIP)**. Each Excel has a **Summary** sheet with the counts and a **Reconciliation** sheet. Filter its **Result** column:
|
|
||||||
|
|
||||||
| Result | Meaning | What you do |
|
|
||||||
|---|---|---|
|
|
||||||
| Matched | Same date of service, first name and a last name | Nothing |
|
|
||||||
| Missing in Waystar | An Aquilaehr visit with no Waystar claim | Follow up. If the Note says "Claim ID … is in Waystar with DOS …", the claim exists with another date |
|
|
||||||
| Missing in Aquilaehr | A Waystar claim with no Aquilaehr visit | Follow up. If the Note says "Claim ID … is in Aquilaehr with Visit Date …", the visit exists with another date |
|
|
||||||
| Duplicate in Waystar | "Same patient + DOS already matched to another Waystar claim" | Check for a double claim |
|
|
||||||
|
|
||||||
## 4. When something goes wrong
|
|
||||||
|
|
||||||
**How it shows:** a red or orange dot in the activity list, an orange or red lane, or the status "Stopped". The line names the location and the portal.
|
|
||||||
|
|
||||||
| ID | Message you see | What it means | What you do |
|
|
||||||
|---|---|---|---|
|
|
||||||
| E01 | "Couldn't sign in to *Portal* in time. Check the login details, then run again." | Nothing was downloaded from that portal. Its lane stays on "Signing in…", then turns red "Stopped" | Run again once. Fails again: email us (only we can change the logins) |
|
|
||||||
| E02 | "Couldn't download *Location* from *Portal*. This location wasn't found in *Portal*." | The location was renamed or removed in the portal | Email us. Re-running won't help |
|
|
||||||
| E03 | "Couldn't download *Location* from *Portal*. *Portal* took too long to respond." | The portal was too slow | Download the good reports, run again later. Fails twice: email us |
|
|
||||||
| E04 | "Couldn't download *Location* from Aquilaehr. Aquilaehr opened a different location than expected." | Aquilaehr showed the wrong practice | Run again. Fails twice: email us |
|
|
||||||
| E05 | "Couldn't download *Location* from *Portal*. Try running again. If it keeps failing, open the technical log below." | Any other download problem | Run again. Fails twice: email us |
|
|
||||||
| E06 | "*Portal* finished, but these locations couldn't be downloaded: *names*" | Summary of E02 to E05 | Those locations have no report, or a one-sided one |
|
|
||||||
| E07 | "*Location* has exactly the same *Portal* data as *Location*. Please check this location." | One may hold the other's data | **Don't use those two reports.** Run again (expected only when both have no data) |
|
|
||||||
| E08 | "Skipped *Location*: nothing was downloaded from Aquilaehr" | No report was built for that location | Look for its red Aquilaehr line (E01 to E05) |
|
|
||||||
| E09 | "Check *Location*: fewer than half of the visits matched. The wrong practice may have been downloaded." | Most visits didn't match | **Before re-running, check its Note column.** Dates exactly one day off the DOS: don't re-run, email us. Otherwise run again |
|
|
||||||
| E10 | "Running…" with no new activity line for 10 minutes | The run is stuck | Email us. Don't start another run |
|
|
||||||
| E11 | "Something unexpected went wrong. The technical log below has the details.", or "Stopped" with no red line that explains it | An error without a plain message, e.g. a new Waystar security question | Email us with the last 20 lines of **Technical log** |
|
|
||||||
| E12 | A location has no report and no red line names it | A failed Waystar download is not always listed | Email us |
|
|
||||||
| E13 | The lanes say "Ready" and the status is empty, although a run was started | The server restarted and the run was lost | Download what is listed, then run again |
|
|
||||||
| E14 | "That password isn't right. Try again." or "Enter your password." | Wrong or empty password | Check for "Caps Lock is on" and type it again |
|
|
||||||
| E15 | "Sign-in failed. Try again.", "Can't reach the server. Try again.", or a 404 / 502 page | The server or the network has a problem | Try again in 5 minutes, then email us |
|
|
||||||
|
|
||||||
**Don't:**
|
|
||||||
- Click **Run reconciliation** before downloading the reports you need: it deletes them.
|
|
||||||
- Ask for a server restart or redeploy during a run: the run is lost.
|
|
||||||
- Sign in to Waystar or Aquilaehr with the bot's account during a run.
|
|
||||||
|
|
||||||
**To stop it:** there is no Stop button, and closing the page doesn't stop it. Let it finish, or email us and we stop it on the server.
|
|
||||||
|
|
||||||
## 5. Email us
|
|
||||||
|
|
||||||
Email **dev@example.com** with **the RPA manager** (manager@example.com) in CC when section 4 says "email us", or when the same error comes back after one re-run. Answer: same working day.
|
|
||||||
|
|
||||||
```
|
|
||||||
To: dev@example.com
|
|
||||||
CC: manager@example.com
|
|
||||||
Subject: MEK Charge Reconciliation - E<number> - <date>
|
|
||||||
|
|
||||||
Run started: <first line of the activity list>
|
|
||||||
Error: E<number> - <the message, copied>
|
|
||||||
Location / portal:
|
|
||||||
What I did: <e.g. ran it again once>
|
|
||||||
Attached: screenshot of the Run box
|
|
||||||
```
|
|
||||||
|
|
||||||
**Never send:** the sign-in password, or the Excel reports (they hold patient names).
|
|
||||||
@@ -119,16 +119,50 @@ def to_pdf(docx_path):
|
|||||||
return (pdf if pdf.exists() else None), pages
|
return (pdf if pdf.exists() else None), pages
|
||||||
|
|
||||||
|
|
||||||
|
SAMPLE = """# Sample Bot Handover SOP
|
||||||
|
|
||||||
|
Version 1.0 · Problems: email dev@example.com, CC manager@example.com (section 5)
|
||||||
|
|
||||||
|
## 1. How to run
|
||||||
|
|
||||||
|
1. Open **Sample Bot** and click **Run**.
|
||||||
|
|
||||||
|
## 2. What you see while it runs
|
||||||
|
|
||||||
|
| Where on the screen | What it shows |
|
||||||
|
|---|---|
|
||||||
|
| Status | "Running…" then "Finished" |
|
||||||
|
|
||||||
|
## 3. Result
|
||||||
|
|
||||||
|
| Status | Meaning | What you do |
|
||||||
|
|---|---|---|
|
||||||
|
| Done | Posted | Nothing |
|
||||||
|
|
||||||
|
## 4. When something goes wrong
|
||||||
|
|
||||||
|
| ID | Message you see | What it means | What you do |
|
||||||
|
|---|---|---|---|
|
||||||
|
| E01 | "Couldn't open *Item*" | The app was slow | Run again |
|
||||||
|
|
||||||
|
## 5. Email us
|
||||||
|
|
||||||
|
```
|
||||||
|
To: dev@example.com
|
||||||
|
CC: manager@example.com
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def selfcheck():
|
def selfcheck():
|
||||||
example = Path(__file__).parent / "reference" / "mek-charge-reconciliation.md"
|
sop = SAMPLE
|
||||||
sop = "# " + example.read_text(encoding="utf-8").split("\n---\n", 1)[1].split("\n# ", 1)[1]
|
|
||||||
out = Path(tempfile.mkdtemp()) / "HANDOVER-SOP.docx"
|
out = Path(tempfile.mkdtemp()) / "HANDOVER-SOP.docx"
|
||||||
convert(sop, out)
|
convert(sop, out)
|
||||||
doc = Document(out)
|
doc = Document(out)
|
||||||
heads = [p.text for p in doc.paragraphs if p.style.name.startswith("Heading")]
|
heads = [p.text for p in doc.paragraphs if p.style.name.startswith("Heading")]
|
||||||
assert doc.paragraphs[0].text.endswith("Handover SOP"), doc.paragraphs[0].text
|
assert doc.paragraphs[0].text.endswith("Handover SOP"), doc.paragraphs[0].text
|
||||||
assert [h.split(".")[0] for h in heads if h[:1].isdigit()] == [str(n) for n in range(1, 6)], heads
|
assert [h.split(".")[0] for h in heads if h[:1].isdigit()] == [str(n) for n in range(1, 6)], heads
|
||||||
assert len(doc.tables) >= 4, len(doc.tables)
|
assert len(doc.tables) == 3, len(doc.tables)
|
||||||
assert doc.tables[0].cell(0, 0).text == "Where on the screen", doc.tables[0].cell(0, 0).text
|
assert doc.tables[0].cell(0, 0).text == "Where on the screen", doc.tables[0].cell(0, 0).text
|
||||||
assert not any("**" in p.text or "|---" in p.text for p in doc.paragraphs)
|
assert not any("**" in p.text or "|---" in p.text for p in doc.paragraphs)
|
||||||
assert words(sop) <= MAX_WORDS, words(sop)
|
assert words(sop) <= MAX_WORDS, words(sop)
|
||||||
|
|||||||
+15
-17
@@ -45,29 +45,27 @@ def test_ai_skill_references_files_that_exist():
|
|||||||
assert not missing
|
assert not missing
|
||||||
|
|
||||||
|
|
||||||
def test_handoff_skill_references_files_that_exist():
|
def handoff_skill():
|
||||||
skill = ROOT / "skills" / "rpa-bot-handoff"
|
return (ROOT / "skills" / "rpa-bot-handoff" / "SKILL.md").read_text(encoding="utf-8")
|
||||||
paths = re.findall(r"`(templates/[\w./-]+)`", (skill / "SKILL.md").read_text(encoding="utf-8"))
|
|
||||||
assert len(paths) >= 3
|
|
||||||
assert not [p for p in paths if not (skill / p).exists()]
|
|
||||||
|
|
||||||
|
|
||||||
def test_handoff_skill_stays_short():
|
def test_handoff_skill_is_one_short_file_plus_the_converter():
|
||||||
skill = (ROOT / "skills" / "rpa-bot-handoff" / "SKILL.md").read_text(encoding="utf-8")
|
files = sorted(p.relative_to(ROOT / "skills" / "rpa-bot-handoff").as_posix()
|
||||||
assert len(skill.split()) <= 500, len(skill.split())
|
for p in (ROOT / "skills" / "rpa-bot-handoff").rglob("*") if p.is_file())
|
||||||
assert len(re.findall(r"^\d+\. ", skill.split("## Don't miss")[1], re.MULTILINE)) == 6
|
assert files == ["SKILL.md", "templates/to_docx.py"], files
|
||||||
|
assert len(handoff_skill().splitlines()) <= 60
|
||||||
|
assert "templates/to_docx.py" in handoff_skill()
|
||||||
|
|
||||||
|
|
||||||
def test_handoff_sop_has_five_sections_in_order():
|
def test_handoff_skill_lists_six_dont_miss_checks():
|
||||||
sop = (ROOT / "skills" / "rpa-bot-handoff" / "templates" / "HANDOVER-SOP.md").read_text(encoding="utf-8")
|
assert len(re.findall(r"^\d+\. ", handoff_skill().split("Don't miss")[1], re.MULTILINE)) == 6
|
||||||
assert re.search(r"^# \{\{PROJECT_NAME\}\} Handover SOP$", sop, re.MULTILINE)
|
|
||||||
assert [int(n) for n in re.findall(r"^## (\d+)\.", sop, re.MULTILINE)] == list(range(1, 6))
|
|
||||||
|
|
||||||
|
|
||||||
def test_handoff_sop_emails_the_developer_with_the_manager_in_cc():
|
def test_handoff_sop_shape_has_five_sections_and_to_cc():
|
||||||
sop = (ROOT / "skills" / "rpa-bot-handoff" / "templates" / "HANDOVER-SOP.md").read_text(encoding="utf-8")
|
shape = handoff_skill().split("```markdown")[1].split("```")[0]
|
||||||
email = sop.split("## 5.")[1]
|
assert "# <Project Name> Handover SOP" in shape
|
||||||
assert "To: {{DEV_EMAIL}}" in email and "CC: {{MANAGER_EMAIL}}" in email
|
assert [int(n) for n in re.findall(r"^## (\d+)\.", shape, re.MULTILINE)] == list(range(1, 6))
|
||||||
|
assert "To: <developer>" in shape and "CC: <manager>" in shape
|
||||||
|
|
||||||
|
|
||||||
def test_handoff_docx_selfcheck():
|
def test_handoff_docx_selfcheck():
|
||||||
|
|||||||
Reference in new issue
Block a user