Rules-as-code · Plain-English guide
How the digitised rules work out which licences and permits an activity in a Victorian State forest needs, and what the application must contain. Written for a non-technical reader.
This ruleset asks one question: “which licences or permits does this application need?” The applicant describes what they intend to do in a State forest, and for each intended activity the rules switch on a matching requirement.
The core pattern
Each regulated activity has a trigger. If the applicant's answers match it, the rules mark the matching Permit required.
One extra idea · lists
Where an applicant lists several extra activities, the rules apply the same checks to each item in the list.
One extra idea · must-do
Beyond permitted/forbidden, a rule can mark something Obligated — a step the applicant must complete (here, stating a purpose once any permit is triggered).
You provide a fact · Rules work out a conclusion.
An individual or a business, with an address and contact details.
Yes/no intentions that drive every permit decision, plus supporting detail (area flags, equipment, cattle, written authorities).
Each switched on when its trigger is met.
Seven independent checks each look at what the applicant intends and, if it matches, switch on the matching requirement. They don't interact — an application can trigger any number.
| If the applicant intends to… | …when this is true | Then this is |
|---|---|---|
| Leave gates open or damage a gate | Either is “yes” | Gate permit required |
| Fell a survey-marked tree / deface a survey mark | Either is “yes” | Tree-felling licence required |
| Enter a restricted area | Area is experimental, nursery, plantation or fenced — and known to be prohibited | Restricted-area permit required |
| Interfere with research equipment | Equipment is for experimentation and used in research | Research permit required |
| Sell goods or services | “yes” | Permit to sell required |
| Enter reserved forest with cattle | “yes” | Cattle-entry permit required |
| Cut, dig or take away forest produce | “yes” | Take-away permit required |
Two triggers are compound — more than one condition must line up:
One final rule ties the checks together. If the application has triggered any licence or permit, stating a purpose becomes Obligated — the applicant must do it.
Mandatory applicant details: title, given name and family name, plus the address's street number, street name, suburb, state and postcode are Required; the unit number is Optional.
Additional activities are handled with a “for each” check: for every extra activity the applicant lists, the permitted act and the person or class it applies to are required, and an additional-activity request is recorded (which in turn obliges a purpose).
Coverage at a glance
9 test suite(s), 22 scenario(s), 19 expectation(s) in total. 19 scenario(s) assert an outcome; 3 assert nothing (inputs only).
Scenarios that assert nothing exercise the rules but cannot pass or fail — they are a coverage gap worth noting.
Coverage here is genuinely assertive: 19 of the 22 scenarios check an outcome, and the suites are organised one-per-permit. Most flag checks carry both a positive case (trigger present → permit required) and a negative one (trigger absent → not required), which is exactly the shape you want. The two compound triggers are tested on both sides — the restricted-area suite pairs a “known experimental area” (required) with an “unknown experimental area” (not required), and the research suite separates “for experimentation” from “used in research”.
The gaps worth closing: (1) the purpose-obligation rule is untested — no scenario checks that isPurposeSpecified becomes Obligated once any permit fires; (2) the grazing-licence flag is never asserted, which is consistent with no rule ever setting it (see Observations); (3) the “for each” additional-activities path has a single scenario that asserts nothing, so the per-item Written-Authority requirements and isAdditionalActivityRequested go unverified; (4) the applicant name/address requirements are unchecked — both “8 Applications” scenarios assert nothing; and (5) no scenario triggers several permits at once, so the independence of the checks is untested (low risk, but cheap to add). The restricted-area suite also omits the nursery and fenced branches, and the “prohibited, but not a special-area type” combination.
Given these inputs
| @id: | F6lsPSSQB3C68tf4g4LN4YqB |
| @type: | Regsoft |
| @name: | debug-hang-repro |
| application.damageGate: | False |
| application.leaveGatesOpen: | False |
Then expect
Given these inputs
| @id: | F6lsPSSQB3C68tf4g4LN4YqB |
| @type: | Regsoft |
| @name: | debug-hang-repro |
| application.damageGate: | False |
| application.leaveGatesOpen: | True |
Then expect
Given these inputs
| @id: | F6lsPSSQB3C68tf4g4LN4YqB |
| @type: | Regsoft |
| @name: | debug-hang-repro |
| application.damageGate: | True |
| application.leaveGatesOpen: | False |
Then expect
Given these inputs
| @id: | k8ssAjfvJqd1bhQq8NTYcNcI |
| @type: | Regsoft |
| @name: | Not asking to feel does not receive a licence |
| application.defaceInscribedSurveyMark: | False |
| application.fellTreeBearingInscribedSurveyMark: | False |
Then expect
Given these inputs
| @id: | k8ssAjfvJqd1bhQq8NTYcNcI |
| @type: | Regsoft |
| @name: | Not asking to feel does not receive a licence |
| application.defaceInscribedSurveyMark: | True |
| application.fellTreeBearingInscribedSurveyMark: | False |
Then expect
Given these inputs
| @id: | k8ssAjfvJqd1bhQq8NTYcNcI |
| @type: | Regsoft |
| @name: | Not asking to feel does not receive a licence |
| application.defaceInscribedSurveyMark: | False |
| application.fellTreeBearingInscribedSurveyMark: | True |
Then expect
Given these inputs
| @id: | qny2geqQe4pNOp7YeGvvl5Wl |
| @type: | Regsoft |
| @name: | Not entering restricted area = no permit required |
| application.enterArea.areaIsFenced: | False |
| application.enterArea.isExperimentalArea: | False |
| application.enterArea.isPlantation: | False |
| application.enterArea.isTreeNursery: | False |
| application.enterArea.knownToBeProhibited: | False |
Then expect
Given these inputs
| @id: | qny2geqQe4pNOp7YeGvvl5Wl |
| @type: | Regsoft |
| @name: | Not entering restricted area = no permit required |
| application.enterArea.areaIsFenced: | False |
| application.enterArea.isExperimentalArea: | True |
| application.enterArea.isPlantation: | False |
| application.enterArea.isTreeNursery: | False |
| application.enterArea.knownToBeProhibited: | True |
Then expect
Given these inputs
| @id: | qny2geqQe4pNOp7YeGvvl5Wl |
| @type: | Regsoft |
| @name: | Not entering restricted area = no permit required |
| application.enterArea.areaIsFenced: | False |
| application.enterArea.isExperimentalArea: | False |
| application.enterArea.isPlantation: | True |
| application.enterArea.isTreeNursery: | False |
| application.enterArea.knownToBeProhibited: | True |
Then expect
Given these inputs
| @id: | qny2geqQe4pNOp7YeGvvl5Wl |
| @type: | Regsoft |
| @name: | Not entering restricted area = no permit required |
| application.enterArea.areaIsFenced: | False |
| application.enterArea.isExperimentalArea: | True |
| application.enterArea.isPlantation: | False |
| application.enterArea.isTreeNursery: | False |
| application.enterArea.knownToBeProhibited: | False |
Then expect
Given these inputs
| @id: | H4cj2ZRXvgOiPaf9nuhbg8m8 |
| @type: | Regsoft |
| @name: | Not interfering does not require a permit |
| application.equipmentToInterfereWith.isForExperimentation: | False |
| application.equipmentToInterfereWith.isUsedInConnectionWithResearchActivities: | False |
Then expect
Given these inputs
| @id: | H4cj2ZRXvgOiPaf9nuhbg8m8 |
| @type: | Regsoft |
| @name: | Not interfering does not require a permit |
| application.equipmentToInterfereWith.isForExperimentation: | True |
| application.equipmentToInterfereWith.isUsedInConnectionWithResearchActivities: | True |
Then expect
Given these inputs
| @id: | H4cj2ZRXvgOiPaf9nuhbg8m8 |
| @type: | Regsoft |
| @name: | Not interfering does not require a permit |
| application.equipmentToInterfereWith.isForExperimentation: | True |
| application.equipmentToInterfereWith.isUsedInConnectionWithResearchActivities: | False |
Then expect
Given these inputs
| @id: | AT4rIdcnyHt0o8adZsP3zKUZ |
| @type: | Regsoft |
| @name: | Not selling goods does not require a permit |
| application.sellGoodsOrServices: | False |
Then expect
Given these inputs
| @id: | s0YjBa6nEECpMj9sTVznK6MW |
| @type: | Regsoft |
| @name: | Selling goods requires a permit |
| application.sellGoodsOrServices: | True |
Then expect
Given these inputs
| @id: | cBh7YLaZjGoUChfZJeYjWNTd |
| @type: | Regsoft |
| @name: | Not grazing does not require a licence |
| application.enterForestWithCattle: | False |
Then expect
Given these inputs
| @id: | 77aePcGrPkdDar3OxuSpyxqk |
| @type: | Regsoft |
| @name: | Entering with cattle requires a licence |
| application.enterForestWithCattle: | True |
Then expect
Given these inputs
| @id: | IGdismlXnANaGE5uv5A89nCa |
| @type: | Regsoft |
| @name: | Information not required if not applying for licence |
| application.isAdditionalActivityRequested: | False |
| application.isGatePermitRequired: | False |
| application.isGrazingLicenceRequired: | False |
| application.isPermitToEnterForestWithCattleRequired: | False |
| application.isPermitToInterfereWithResearchActivityRequired: | False |
| application.isPermitToSellRequired: | False |
| application.isRestrictedAreaPermitRequired: | False |
| application.isTreeFellingLicenceRequired: | False |
Then expect
Nothing asserted — this scenario has no expectations.
Given these inputs
| @id: | S3GGBDe83rRcLZqHMhahF63I |
| @type: | Regsoft |
| @name: | Data required for licence |
| application.isAdditionalActivityRequested: | False |
| application.isGatePermitRequired: | True |
| application.isGrazingLicenceRequired: | False |
| application.isPermitToEnterForestWithCattleRequired: | False |
| application.isPermitToInterfereWithResearchActivityRequired: | False |
| application.isPermitToSellRequired: | False |
| application.isRestrictedAreaPermitRequired: | False |
| application.isTreeFellingLicenceRequired: | False |
Then expect
Nothing asserted — this scenario has no expectations.
Given these inputs
| @id: | iu7N0WLfzF5C6JDBOSZgPQm1 |
| @type: | Regsoft |
| @name: | Not cutting does not require a licence |
| application.cutDigOrTakeAwayForestProduce: | False |
Then expect
Given these inputs
| @id: | Jy01VlXXpN461UhzTj6Z5eMU |
| @type: | Regsoft |
| @name: | Removing forest produce needs a licence |
| application.cutDigOrTakeAwayForestProduce: | True |
Then expect
Given these inputs
| @id: | gPIKTADD8pIz4WkpkGtF2yXx |
| @type: | Regsoft |
| @name: | No additional activities does not require additional permissions |
Then expect
Nothing asserted — this scenario has no expectations.
1 · A grazing licence that's never decided
The data model defines a “grazing licence required” conclusion, and the purpose test checks for it — but no rule ever sets it. The gate section is even labelled “to decide if a grazier licence is required”, yet it switches on the gate permit. The grazing-licence path looks unfinished.
2 · Duplicated requirement rules
The applicant's name is made required in two places, and the street number both inside the address group and again as a stray standalone rule. Harmless but redundant.
3 · An empty section
“9 Conditions of all licences and permits” contains no rules yet — a placeholder for logic not added.
4 · “Worked-out” flags labelled as user input
Several “is a permit required” flags are calculated by the rules but tagged in the data model as things the applicant enters — it works, but could mislead a reader or the question wizard.