Turning a Home Care Audit Evidence List into Data: An Outcome Coverage Index for Support at Home Providers

Originally based on our article the 7 strengthened Aged Care Quality Standards explained for home care on rostery.com.au. This version is rewritten for developers, data people and operations staff who look after the systems behind a Support at Home provider.
When a Category 4 home care provider renews its registration, the Aged Care Quality and Safety Commission asks for evidence in a fairly structured way. Its Care Delivery Evidence Collection Tool for Categories 4 and 5 (the CDECT, last updated 17 July 2026) lists 31 numbered documents and records to send before the audit opening meeting. Each row names the evidence, the outcomes it relates to and the time period it should cover. A second, shorter list sets out what the audit team may ask for while it's on site.
That's a schema, even if it arrives as a Word document. If you treat it as one, you can answer useful questions weeks before an audit letter: which outcomes have nothing behind them, which registers are stale for the window being asked about, and which older people are likely to end up in the sample.
This post builds a small Python model for each of those questions. It's deliberately plain: dataclasses, sets and a few pure functions. You can port it to SQL or whatever your reporting layer uses.
General information only, not legal advice. The outcome list comes from the Commission's Strengthened Quality Standards guidance pages and the evidence list from the CDECT for Categories 4 and 5, both read on 11 November 2026. Check the current versions before relying on any of this.
Start with the outcomes that apply to you
The strengthened standards have 7 standards and 33 outcomes. Three outcomes are written in two parts (2.2a and 2.2b, 2.6a and 2.6b, 4.1a and 4.1b), so in practice you work with outcome statements rather than outcome numbers.
Which statements apply depends on registration category. A Support at Home provider is registered in Category 4 with the service type "Care management", which brings in Standards 1 to 4 plus Outcome 5.1, clinical governance. The CDECT itself carries a footnote saying Outcome 5.1 applies only to the care management and restorative care management service types. A provider that also delivers nursing is in Category 5 and meets all of Standard 5.
Put that in a table rather than in someone's head:
from dataclasses import dataclass @dataclass(frozen=True) class Outcome: code: str # "2.6a" title: str standard: int OUTCOMES = [ Outcome("1.1", "Person-centred care", 1), Outcome("1.2", "Dignity, respect and privacy", 1), Outcome("1.3", "Choice, independence and quality of life", 1), Outcome("1.4", "Transparency and agreements", 1), Outcome("2.1", "Partnering with individuals", 2), Outcome("2.2a", "Culture that supports aged care workers", 2), Outcome("2.2b", "Culture that supports individuals", 2), Outcome("2.3", "Accountability, quality system, policies", 2), Outcome("2.4", "Risk management", 2), Outcome("2.5", "Incident management", 2), Outcome("2.6a", "Complaints and feedback: workers", 2), Outcome("2.6b", "Complaints and feedback: individuals", 2), Outcome("2.7", "Information management", 2), Outcome("2.8", "Workforce planning", 2), Outcome("2.9", "Human resource management", 2), Outcome("2.10", "Emergency and disaster management", 2), Outcome("3.1", "Assessment and planning", 3), Outcome("3.2", "Delivery of funded aged care services", 3), Outcome("3.3", "Communicating for safety and quality", 3), Outcome("3.4", "Planning and coordination", 3), Outcome("4.1a", "Environment: services in the person's home", 4), Outcome("4.1b", "Environment: services elsewhere", 4), Outcome("4.2", "Infection prevention and control", 4), Outcome("5.1", "Clinical governance", 5), # 5.2 to 5.7 omitted here: they apply in full to Category 5 and 6 ] def applicable(categories: set[int], service_types: set[str]) -> list[Outcome]: out = [] for o in OUTCOMES: if o.standard <= 4 and categories & {4, 5, 6}: out.append(o) elif o.code == "5.1" and ( categories & {5, 6} or (4 in categories and service_types & {"care management", "restorative care management"}) ): out.append(o) return out sah = applicable({4}, {"care management", "personal care"}) assert len(sah) == 24 That assert is worth keeping in your test suite. Twenty-three statements from Standards 1 to 4 plus 5.1 gives the 24 a Support at Home provider is assessed against, and if a refactor ever changes the count you want to know straight away.
Encode the evidence list as rows
Each CDECT row has four fields that matter to us: a number, a description, the outcomes it relates to, and a time period. Some rows say "Various" instead of listing outcomes. Keep that as its own value, because "Various" is not the same as "none".
from dataclasses import dataclass, field @dataclass(frozen=True) class EvidenceRequest: no: int title: str outcomes: frozenset[str] = field(default_factory=frozenset) various: bool = False window: str = "Current" CDECT = [ EvidenceRequest(1, "List of current management and workers", frozenset({"2.2a", "2.6a", "2.8", "2.9"}), window="Latest"), EvidenceRequest(5, "Worker roster or shift allocation sheet", frozenset({"2.8", "2.9"}), window="Last 4 weeks"), EvidenceRequest(8, "Training and induction register", frozenset({"2.8", "2.9"}), window="Last 12 months"), EvidenceRequest(11, "Data on unfilled shifts", frozenset({"2.2a", "2.8", "2.9"}), window="Last 4 weeks"), EvidenceRequest(12, "List of older people with risk factors", various=True), EvidenceRequest(17, "Risk register", frozenset({"1.3", "2.4", "2.10", "3.1", "3.2", "4.1b", "4.2", "5.3", "5.5"})), EvidenceRequest(18, "Complaints and feedback register", frozenset({"2.6a", "2.6b"}), window="Past 12 months"), EvidenceRequest(19, "Incident registers incl. SIRS notifications", frozenset({"2.5", "3.1", "3.3"}), window="Past 3 months"), EvidenceRequest(20, "Trend analysis of incidents and complaints", frozenset({"2.3", "2.5", "2.6a", "2.6b"}), window="Past 12 months"), EvidenceRequest(27, "Clinical meeting minutes", frozenset({"5.1"}), window="Last 4 meetings"), EvidenceRequest(29, "Older people and supporter meeting minutes", frozenset({"1.1", "1.3", "2.1", "3.3"}), window="Last 4 meetings"), # ...the full list has 31 rows; copy them from the current CDECT ] Notice that outcomes from Standard 5 beyond 5.1 turn up in some rows (the risk register is tagged 5.3 and 5.5). The tool covers Category 4 and 5 together, so filter the tags against your own applicable set rather than trusting the row.
Check coverage, and read the gaps carefully
Now the first useful report: which of your applicable outcomes has no numbered pre-audit request tagged against it?
def coverage(requests, outcomes): codes = {o.code for o in outcomes} tagged = set().union(*(r.outcomes for r in requests)) & codes return sorted(codes - tagged) print(coverage(CDECT, sah)) # with all 31 rows loaded # ['1.2', '1.4', '2.2b', '2.7', '3.4'] We ran this over all 31 rows of the July 2026 version. Five Support at Home outcomes aren't tagged on any numbered pre-audit document: dignity, respect and privacy (1.2), transparency and agreements (1.4), the culture that supports individuals (2.2b), information management (2.7), and planning and coordination (3.4).
That doesn't mean the Commission ignores them. It means the evidence for them comes from somewhere else: the "Various" rows, interviews with older people and workers, observation, and the second list of records the audit team may ask for during the audit. That list includes agreements with older people, budgets and monthly statements, consent and dignity of risk forms, the tools used to share information with older people and workers, and progress or file notes for the previous 60 days. It carries no outcome tags, so map it yourself. Our own mapping, not the Commission's, looks like this:
DURING_AUDIT = { "Agreements with older people": {"1.4"}, "Budget and monthly statements": {"1.4"}, "Consent and dignity of risk forms": {"1.3"}, "Communication tools, interpreters, other formats": {"2.7", "3.3"}, "Progress or file notes, previous 60 days": {"3.2", "3.3"}, "Current care and services plans": {"1.1", "3.1"}, } The practical point is that outcome 1.4 sits almost entirely on records the auditors may ask for on the day. Those are exactly the records where home care has been weakest. The Department's first Support at Home payment integrity review found only 21% of the 262 monthly statements it reviewed had every required item, and the Commission's April to June 2026 data counted 1,011 home care concerns about fees and charges, or how they were communicated. Your coverage report should flag 1.4 for a manual check even though nothing is "missing" from the pre-audit list.
Normalise the time windows
The "Time period" column mixes three kinds of window:
- Point in time: "Latest" and "Current".
- Rolling date ranges: "Last 4 weeks", "Past 3 months", "Past 12 months", and "previous 60 days" for progress notes.
- Counts: "Last 4 meetings".
The count-based one catches people out. If a team meets every quarter, the last four meetings reach back a year. If it met twice and then stopped, no date filter will tell you; you need the count.
from datetime import date, timedelta def window_ok(records: list[date], window: str, today: date) -> bool: if window in ("Latest", "Current"): return bool(records) # plus a "still in force" check elsewhere if window == "Last 4 meetings": return len(records) >= 4 days = {"Last 4 weeks": 28, "Past 3 months": 92, "Past 12 months": 366, "Previous 60 days": 60}[window] since = today - timedelta(days=days) return any(d >= since for d in records) A rolling window passing doesn't prove much on its own. An incident register with one entry in three months passes the check but may tell an auditor something about reporting culture. Report the count alongside the pass, and let a person decide what's normal for the service.
"Current" also needs its own rule per record type. For care plans it means a plan in force with a review date in the future. For worker checks it means not expired. For an emergency plan it means reviewed on the cycle your own policy sets. Keep those rules next to the request, not buried in a report query.
Build the sample list before you're asked for it
Row 12 asks for a complete list of older people receiving care, and a list of those with particular risk factors. The factors include palliative and end of life care needs, specialised nursing needs, communication difficulties (cognitive or sensory impairment, disability, culturally and linguistically diverse backgrounds), high-risk medications such as psychotropics or insulin, any restraint or seclusion, a recent history of falls, a transition to or from hospital or another provider in the last 3 months, living alone with limited outside contact, oxygen, a stoma, enteral feeding, a catheter, needing a higher level of care than they currently receive, greater than expected unspent funds, self-managing Support at Home funding, and being represented by a public guardian.
Most of these can be derived from data you already hold. A few can't, and the honest design is to say so:
from enum import Enum class Source(Enum): DERIVED = "derived from records" CONFIRM = "needs a care manager to confirm" RISK_FLAGS = { "recent_falls": (Source.DERIVED, "incident type = fall, last 90 days"), "hospital_transition": (Source.DERIVED, "hospital or transfer record, last 3 months"), "high_risk_meds": (Source.DERIVED, "active medication in a high-risk class list"), "restraint": (Source.DERIVED, "restrictive practice recorded"), "unspent_funds_high": (Source.DERIVED, "unspent balance above your own threshold"), "self_manages": (Source.DERIVED, "funding management flag"), "lives_alone_limited": (Source.CONFIRM, "living situation plus contact pattern"), "needs_higher_care": (Source.CONFIRM, "care manager judgement or pending reassessment"), "communication": (Source.CONFIRM, "cognitive, sensory, disability or language needs"), } "Greater than expected" unspent funds has no number in the tool, so the threshold is yours to set and to explain. Write it down. The same goes for "limited contact outside of the provider".
This list does more than satisfy row 12. The people on it are the ones whose records an auditor is most likely to read closely, so it's also a good list for your own file reviews in the months before an audit.
Map each request to its system of record
Last step: for every request, record where the evidence lives and who owns it. In most small providers the answer is spread across a rostering tool, an HR folder, spreadsheets for registers and an accounting package for statements. A short table makes the gaps obvious:
| Request | System of record | Owner | Window |
|---|---|---|---|
| Worker list, roster, unfilled shifts | Rostering system | Rostering lead | Latest / 4 weeks |
| Worker checks, training register | HR or worker compliance | HR | Current / 12 months |
| Incident register, SIRS notifications | Incident system | Quality manager | 3 months |
| Complaints register | Complaints system | Quality manager | 12 months |
| Care and services plans | Care management | Care partners | Current |
| Agreements, budgets, monthly statements | Billing and statements | Finance | Current |
| Meeting minutes | Shared drive | Each meeting's chair | Last 4 meetings |
If a row has two systems in the owner column, expect a reconciliation problem at audit time.
In Rostery, a few of these joins are built in. The aged care complaints register has a Linked Quality Standard field on each complaint, so the register can be filtered by the standard it's evidence against. Aged care care plans carry a Review due date that turns amber within 30 days and red once it has passed, which maps neatly onto a "Current" rule. Support at Home statements and claims are generated for each participant's plan every month, including months with no services. None of that replaces the mapping exercise; it just means fewer columns of the table point at spreadsheets.
For a plain-language refresher on the standards themselves, the Aged Care Quality Standards glossary entry is a quick read, and our Blogger post on which Aged Care Quality Standards a home care provider actually meets walks through the registration categories. If incidents are your next build, our earlier dev.to post on a SIRS triage workflow for aged care compliance teams covers reportability and deadlines.
A short checklist for your own build
- Derive the applicable outcome list from registration category and service types, and test the count.
- Store evidence requests as rows with outcomes, a "various" flag and a window.
- Run coverage against applicable outcomes only, and treat untagged outcomes as manual checks, not gaps.
- Map the during-audit records yourself, and label that mapping as yours.
- Normalise windows into point-in-time, rolling and count-based rules, and report counts next to passes.
- Build the risk-factor sample list from data, and mark the flags that need human judgement.
- Give every request one system of record and one owner.
Sources: Aged Care Quality and Safety Commission, Strengthened Quality Standards guidance (outcome pages for Standards 1 to 4 and Outcome 5.1); Strengthened Aged Care Quality Standards page (audit types and ratings); Support at Home provider requirements (Category 4 with care management, Outcome 5.1); Care Delivery Evidence Collection Tool, Categories 4 and 5 (last updated 17 July 2026); Sector performance data, April to June 2026. Department of Health, Disability and Ageing, Support at Home Payment Integrity Rolling Review, cycle 1 summary report. Rostery help and feature pages read 11 November 2026.
Written by the Rostery team in Sydney. Rostery makes rostering, care and billing software for NDIS and aged care providers.
