{"spec":"AIP-BS-COMPLIANCE-CALENDAR","version":"2026-10-03","standard":"compliance-calendar-build-standard","source":"https://aipathway.com.au/explore-ai/compliance-calendar-build-standard","markdown":"https://aipathway.com.au/explore-ai/compliance-calendar-build-standard.md","licence":"CC BY 4.0","how_to_read":"Eight of these ten checks run on your own machine, against the stub, before you talk to anybody. The last one is a live tenant, and that one runs against your own live systems. One is not a software check at all: it asks what you measured before you started.","verdicts":{"pass":"asserted green here","fail":"asserted red here. This is a fixture: it names the check to price","shape_only":"shape holds on the stub, truth needs the live provider","with_us":"cannot be proved on the stub; runs against your own live systems (see with_us_next)","evidence_required":"not a software check. Attach what proves it"},"tally":{"total":10,"onStub":8,"productionOnly":1,"partial":1,"preconditions":1},"envelope_version":"1.0","port_shape":{"read_ledger":{"verb":"read","subject":"ledger"},"read_job":{"verb":"read","subject":"job"},"read_asset":{"verb":"read","subject":"asset"},"read_rule":{"verb":"read","subject":"rule"},"read_contacts":{"verb":"read","subject":"contacts"},"read_segment":{"verb":"read","subject":"segment"},"resolve_address":{"verb":"read","subject":"address"},"write_job":{"verb":"write","subject":"job"},"read_pricebook":{"verb":"read","subject":"pricebook"},"draft_quote":{"verb":"write","subject":"quote"},"write_invoice":{"verb":"write","subject":"invoice"},"write_ledger":{"verb":"write","subject":"ledger"},"record_promise":{"verb":"write","subject":"promise"},"record_service":{"verb":"write","subject":"service_record"},"release_payment":{"verb":"write","subject":"payment"},"talk":{"verb":"say","subject":"turn"},"disclose":{"verb":"say","subject":"disclosure"},"send_sms":{"verb":"say","subject":"sms"},"notify":{"verb":"say","subject":"alert"},"escalate":{"verb":"say","subject":"handoff"},"issue_notice":{"verb":"say","subject":"notice"},"answer":{"verb":"say","subject":"answer"},"publish_report":{"verb":"say","subject":"report"},"record_consent":{"verb":"write","subject":"consent"},"read_file":{"verb":"read","subject":"file"},"write_file":{"verb":"write","subject":"file"},"raise_task":{"verb":"write","subject":"task"},"read_node":{"verb":"read","subject":"node"},"write_node":{"verb":"write","subject":"node"},"read_register":{"verb":"read","subject":"register"},"write_register":{"verb":"write","subject":"register"},"index_passage":{"verb":"attach","subject":"passage"},"search_index":{"verb":"read","subject":"index"},"read_inbox":{"verb":"read","subject":"message"},"file_message":{"verb":"attach","subject":"message"},"write_order":{"verb":"write","subject":"order"},"read_quote":{"verb":"read","subject":"quote"},"write_log":{"verb":"write","subject":"log"},"read_sales":{"verb":"read","subject":"sales"},"read_sale":{"verb":"read","subject":"sale"},"draft_message":{"verb":"write","subject":"draft"},"send_message":{"verb":"say","subject":"message"},"evidence":{"verb":"attach","subject":"evidence"},"cite":{"verb":"attach","subject":"citation"},"rank":{"verb":"decide","subject":"order"},"gate":{"verb":"decide","subject":"gate"}},"provider":{"boundary":{"never":["type a due date; derive it from a dated rule","mark an obligation complete without evidence","certify or attest","guess an anchor date"],"stays_with_person":["accepting an obligation","the owner who declines the work","cross-border interpretation"]},"job":"a compliance calendar that survives a rule change","skill":"compliance-calendar","stub":"local.mock_calendar","production":null,"product":null,"insert":null,"with_us":{"kind":"own_systems","note":"No hosted step. The production check runs against the calendar and document store already in use."}},"with_us_next":"No hosted step. The production check runs against the calendar and document store already in use. There is nothing to buy: your build does this step on the business's own systems. No production run is offered yet, because the live port map is not published, so do not run AIPATHWAY_ENV=production. Run the pass test by hand on the real systems and attach the evidence.","default_path":null,"boundary":{"never":["type a due date; derive it from a dated rule","mark an obligation complete without evidence","certify or attest","guess an anchor date"],"stays_with_person":["accepting an obligation","the owner who declines the work","cross-border interpretation"]},"substrate":{"how_to_read":"These are roles, not products. Work out which you already have by matching `providers[].detect` against the repository, then build or add only the gap. No check asserts against a vendor, so any substrate that answers the role passes the same checks.","requires":[{"role":"record","label":"Somewhere the book lives","need":"Durable storage that the workflow owns the write path to, keyed so the same record can be found twice.","when_missing":"Half a day. Any Postgres will do and the free tiers are ample at this size. The trap is not the database, it is letting people edit around the app that is supposed to own the value.","ports":["read_asset","record_service","evidence","read_rule"]},{"role":"send","label":"Something that sends","need":"Email or SMS from a domain the recipient recognises, with delivery visible enough to tell a bounce from a silence.","when_missing":"An hour for the wiring, longer for the DNS. Sending from a domain you do not own is the single fastest way into a spam folder.","ports":["issue_notice"]},{"role":"surface","label":"Something a person opens","need":"A view of the book that whoever does this job can read and act on without asking a developer.","when_missing":"Start at tier 0 and stop there until the business asks for more. The cheapest surface is not a screen, it is a scheduled email carrying the list, and for one person doing this job that is not a compromise, it is the right answer. On Microsoft 365 or Workspace you can skip straight past this: a list and a sheet are already what people open. Build upward only when two people need the same list at the same time.","tiers":[{"tier":0,"label":"A scheduled digest carrying the list","cost":"About an hour. Needs nothing you do not already have.","satisfiedBy":"send","whenYouNeedIt":"One person does this job. They want to know what is waiting when they sit down, and they act on it from their inbox."},{"tier":1,"label":"A read-only page showing the book","cost":"An afternoon. One query and one table.","whenYouNeedIt":"Somebody needs to look mid-day without waiting for tomorrow's digest, or to answer a customer on the phone."},{"tier":2,"label":"Editable rows, a queue and a log","cost":"A day or two with a coding agent, which is what agents are best at. It is bounded work: the fields are the schema, the queue is whatever escalate hands off, the log is the trace.","whenYouNeedIt":"More than one person shares the book and they need to correct it without treading on each other, and you need to see afterwards who changed what."}],"already_reachable":[{"tier":0,"label":"A scheduled digest carrying the list","because":"this standard already requires the send role, so nothing new is needed for it"}],"ports":["escalate"]}],"registry":"https://aipathway.com.au/substrates.json"},"checks":[{"id":"dates-derived-not-stored","n":1,"title":"Due dates are derived","statement":"Due dates are derived from a dated rule and an anchor, never stored as values.","assertable":"stub","ports":["read_rule","read_asset"],"stimulus":"An obligation with a due date, then a new rule version that changes the interval, effective from a date the runner's clock passes.","assertion":"The due date changes on its own. A stored value that survives the rule change fails, which is the whole point of the check."},{"id":"superseded-versions-retained","n":2,"title":"Superseded rule versions are retained","statement":"Superseded rule versions are retained with their effective dates.","assertable":"stub","ports":["read_rule"],"stimulus":"Two rule versions, and a query about an obligation that fell due under the old one.","assertion":"The old version is still readable with its effective dates, and the historic due date can be explained by the rule that produced it."},{"id":"rules-per-jurisdiction","n":3,"title":"Rules are held per jurisdiction","statement":"Rules are held per jurisdiction where the obligation differs by one.","assertable":"stub","ports":["read_rule"],"stimulus":"The same obligation on two properties in different states.","assertion":"The two due dates differ where the rule differs, from one rule store rather than two builds."},{"id":"unknown-anchor-surfaces","n":4,"title":"An unknown anchor surfaces","statement":"An unknown anchor date is an explicit state that surfaces, not a default.","assertable":"stub","ports":["read_asset","read_rule"],"stimulus":"An obligation whose anchor date is missing.","assertion":"It appears in an explicit unknown-anchor state. A silently defaulted date, including today, fails: a wrong due date that looks confident is worse than a visible gap."},{"id":"evidence-of-completion","n":5,"title":"Completion carries evidence","statement":"Every obligation carries evidence of last completion, not just a completion flag.","assertable":"stub","ports":["evidence","record_service"],"stimulus":"An obligation marked complete with no document attached.","assertion":"The completion is not accepted as evidence on its own, and the obligation is not counted as covered."},{"id":"refusal-is-dated-outcome","n":6,"title":"A refusal is a dated outcome","statement":"An owner or tenant refusal is stored as a dated outcome, and the obligation stays live.","assertable":"stub","ports":["record_service"],"stimulus":"An owner declines the work. The runner then advances the clock past the due date.","assertion":"The refusal is stored with its date, and the obligation is still live and now overdue. A refusal that closes the obligation fails."},{"id":"notice-needs-a-person","n":7,"title":"Nothing sends a legal notice unreleased","statement":"Nothing sends a legal notice without a person releasing it.","assertable":"both","ports":["issue_notice","escalate"],"stimulus":"A breached obligation whose rule names a notice, with no release recorded.","assertion":"No notice is issued. The notice sits awaiting a named release.","stubLimit":"The stub proves nothing leaves without a release event. Only the live path proves the notice that eventually leaves is the one that was released, rather than a regenerated one."},{"id":"breach-does-not-self-clear","n":8,"title":"A breach does not clear itself","statement":"A breached obligation never clears itself when the work is finally done.","assertable":"stub","ports":["record_service","read_rule"],"stimulus":"An obligation allowed to breach, then completed late, then the clock advanced again.","assertion":"The breach remains on the record after completion. The next cycle starts clean; the breach does not disappear from the history."},{"id":"survives-the-builder","n":9,"title":"It survives the builder","statement":"Someone other than the builder can explain what it does, and it runs on an account the business owns.","assertable":"precondition","ports":["read_rule"],"stimulus":"No stimulus. The builder names who else can explain it and whose account the rule store runs on.","assertion":"The runner reports what was declared and never scores it green on its own say-so.","stubLimit":"Not a runtime property. Software cannot prove a second person understands it, and outliving its author is precisely what is being asked about."},{"id":"pass-test","n":10,"title":"The pass test passes","statement":"A rule change moves every open due date derived from it, and a breach that is completed late still reads as breached.","assertable":"production","ports":["read_rule","read_asset","issue_notice"],"stimulus":"A real rule change against the live register, then a real late completion.","assertion":"Every affected obligation re-derives, and nothing that was breached reads clean afterwards.","stubLimit":"Deliberately unpassable on a stub. A stub rule store changes when you tell it to; only a live one changes when somebody else does, which is the failure this exists to catch."}]}