First Australian structured-detector micro-slice: HPI-I and VSN
Status: owner-approved for experimental implementation (G0); see
section 17 for the recorded
decisions and the implementation. Observe and redact only, through G2; no
production blocking.
Evidence cut-off: 3 October 2026 (Australia/Sydney)
Machine-readable companion: au-structured-detector-micro-slice.json
(pinned sources, proposed definitions, 79 synthetic cases)
Governing decisions: ADR 0003,
ADR 0007,
ADR 0010, and the proposed
ADR 0011
This document specifies the first real detector pair. Sections 1–16 are the specification as reviewed; section 17 records the owner decisions and how the built-in detectors implement it. Every rule here is written so the expected output can be derived without the Go implementation.
1. Recommendation
Keep the pair:
| Class | Identifier | Public category (proposed) | Why it is the right first member |
|---|---|---|---|
validated_structured | Healthcare Provider Identifier – Individual (HPI-I) | privacy.pii.health_id.au.hpi_i | A standards body publishes a complete grammar: 16 digits, fixed prefix 800361, and Luhn. A random 16-digit string passes with probability of about 10⁻⁷, so no context gate is needed. Context changes confidence and evidence only, never validation state. Disclosure is restricted by the Healthcare Identifiers Act 2010 s 26(1)(d). |
context_bound_structured | Victorian Student Number (VSN) | privacy.pii.education_id.au.vic.vsn | The issuer publishes an exact but collision-prone shape: nine digits, the same shape as TFN, ACN, and many reference numbers. The detector is useful only because of an exact issuer label or field, which is the property ADR 0010 must demonstrate. The identifier relates to children and is protected under Part 5.3A of the Victorian Education and Training Reform Act 2006. |
Research since the inventory produced three refinements, none of which changes the choice:
- VSN has an unpublished check digit. The 2027 Victorian VET collection
guidelines say the nine-digit format includes a check digit and refer to an
algorithm on the VSN website. No public algorithm was found. VCAA still
describes the VSN as randomly generated, which fits a random body plus a check
digit. VSN therefore remains context-bound and can never be
validatedfrom local evidence. Groundskeeper must not guess the algorithm (compare OD-016 and OD-018). - VSN has published non-identifiers. Valid values are
000000001–999999999.888888888is a temporary code for a student who has not yet received a VSN. Both000000000and888888888are rejected. The standard enrolment form groups the number as 3-3-3, so that grouping is supported. - HPI-I is also legally protected. Section 26(1)(d) of the current compilation (C2026C00415, 19 September 2026) covers the identifier of an individual healthcare provider, not only a patient's IHI. Redacting HPI-I therefore has real privacy value.
Alternatives considered
| Candidate | Class | Why it was not chosen first |
|---|---|---|
IHI (800360 + Luhn) | validated | It is the strongest alternative. It uses the same mechanics, protects patients, and already has a category. However, nearly every Medicare or DVA enrolee has an IHI: tens of millions of values in a space of about 10⁹ Luhn-valid numbers. A synthetic fixture therefore has a few per cent chance of being a real person's IHI. There are roughly one million HPI-Is, so the chance is about 0.1%. Once the validator exists, IHI only needs a different prefix. Recommended as the immediate follow-on. |
HPI-O (800362) | validated | This is an organisational identifier, so it proves less about personal-data handling. |
| ABN | validated | Its mod-89 check is weaker: about 1 in 89 random values pass. ABNs are public business identifiers and should not be redacted by default. |
| Medicare | validated | Its mod-10 check passes about 1 in 10 random values, and the shape collides with ordinary numbers. It needs context gates, so it does not isolate the "checksum alone" case. |
| USI, CRN, VIN, ImmiCard | validated (inventory include) | None has a public checksum, so none can exercise the validated state. |
| Visa Grant Number | context-bound | The label is exact, but the source does not constrain the alphabet ("13 characters"), so the shape is too loose to show that the label, not the shape, supplies the evidence. It is a reasonable second context-bound detector. |
| NSW WWCC, DVA, Ahpra, credit licence | context-bound | Only a prefix, a maximum length, or examples are published. Completing the grammar would require invention. |
| VCAA Student Number (8 digits + letter) | — | It is not in the sourced inventory. It is used here as a hard negative. |
2. Compatibility boundary
- Detectors consume only the canonical segments passed to the existing
Detect(ctx, []model.Segment)interface:content_path,media_type,text, and optionalrole/source. They never readpayloadoradapter_attributes. This holds whether the concurrent API-drift work keeps payload-only requests or derives segments from them. This proposal assumes no outcome for that work. - Output uses only existing finding fields:
category,entity_type,severity,confidence,detector_id,detector_version,detector_class,validation_state,location, andevidence. All evidence kinds already exist incommon.schema.json. No schema change is needed. - The proposed detector IDs are
builtin.pii.au.hpi-iandbuiltin.pii.au-vic.vsn. Both satisfy the current ID pattern. Each detector has one class, its own coverage and version, and can be rolled back independently. Thebuiltin.pii.audetector inpolicies/examples/au-baseline.yamlremains illustrative. - Detectors require no network, filesystem, clock, or randomness permissions. They are deterministic and idempotent, and their runtime is linear in the segment length.
3. Pinned sources
Full records, including claims, licences, and freshness notes, are in the JSON
sources object.
| Key | Source | Pin | Supports |
|---|---|---|---|
hl7-au-base-6.0.0-hpii | HL7 Australia AU Base 6.0.0 StructureDefinition-au-hpii.json (CC0) | 2026-01-15; sha256 d8f3e8d8…a014 | 16 digits, prefix 800361, Luhn (inv-hpii-0..2), system URI. The 7.0.0-ballot1 invariants are unchanged. |
adha-practice-manager-handbook | ADHA My Health Record Handbook for Practice Managers | 2022-07 (digest not captured) | Government corroboration of the prefix and length |
health-gov-healthcare-identifiers | Department of Health, Disability and Ageing | page updated 2025-12-05 | 16-digit identifiers; HPI-I is assigned on Ahpra registration |
hi-act-2010-c2026c00415 | Healthcare Identifiers Act 2010, compilation 22 | 2026-09-19; sha256 80e988fc…026e | s 26(1)(d) use/disclosure restriction and penalties |
vcaa-find-out-student-numbers | VCAA, Find out about student numbers | retrieved 2026-10-03 (dynamic HTML) | Random nine-digit VSN; VCAA Student Number is a different identifier |
vcaa-vsn-providers | VCAA, VSN for Education and Training Providers | retrieved 2026-10-03 | Part 5.3A governs the VSN; no VSNs in class lists |
djsir-vvssc-2027 | DJSIR Victorian VET Student Statistical Collection Guidelines 2027 | PDF 2026-08-11; sha256 e9e3dc12…b71f | Length 9, range, 888888888, existence of a check digit, 3-3-3 form |
vic-etr-act-2006-part-5.3a | Education and Training Reform Act 2006 (Vic) Part 5.3A | authorised version not captured | s 5.3A.10 restriction; s 5.3A.13 student self-disclosure |
Licensing: only the HL7 guide is CC0, so its invariants may be embedded in machine-readable definitions. All other sources are cited as facts and are not reproduced. Labels such as "Victorian Student Number" are names, not protected expression. Do not use licensed HI Service test data.
4. Taxonomy and identity
| HPI-I | VSN | |
|---|---|---|
| Inventory ID → public category | au.health.hpi_i → privacy.pii.health_id.au.hpi_i | au.education.vic_vsn → privacy.pii.education_id.au.vic.vsn |
| Catalogue object ID | groundskeeper.dev/definition/privacy.pii.health_id.au.hpi_i | groundskeeper.dev/definition/privacy.pii.education_id.au.vic.vsn |
entity_type alias | AU_HPI_I | AU_VIC_VSN |
| Jurisdiction / issuer level | AU / commonwealth | AU + AU-VIC / state |
| Classification | personal; government-related identifier; statutorily restricted | personal; government-related identifier; children and young people; statutorily restricted |
| Provisional severity | medium | high |
| Target catalogue file (after ADR 0011) | pii-au/definitions/national/health-identifiers.yaml | pii-au/definitions/subdivisions/au-vic/education-identifiers.yaml |
Rationale: the Healthcare Identifiers Act treats HPI-I as a healthcare
identifier. Placing it under health_id, beside ihi, lets a policy that selects
all Australian healthcare identifiers include it. The subdivision is a taxonomy
level (au.vic) so policies can select Victorian identifiers. ISO 3166-2 remains
in metadata (AU-VIC), as ADR 0011 requires.
5. Shared recognition rules
- Digits: ASCII
0–9only. Fullwidth digits, other UnicodeNddigits, and format characters (Cf, including zero-width characters) are not folded or skipped in v0. They are measured as known gaps (section 10). - Word character: any code point in Unicode category
L*,N*, orM*, orPc(which includes_). - Surface forms: contiguous digits, or the documented grouping (HPI-I 4-4-4-4; VSN 3-3-3). Groups are joined by one repeated separator from U+0020, U+00A0, U+202F, U+002D, U+2010, or U+2011. A value cannot mix separators.
- Value boundary:
- The code points immediately before and after the value are not word characters.
- The value is not preceded by
.or,with a digit before it, and is not followed by.or,with a digit after it. This excludes decimals and thousands grouping. - For grouped forms only, the value is not preceded by a group separator with a digit before it, and is not followed by a group separator with a digit after it. This is the maximal-run rule.
- Normalization: delete the group separator. Spans still cover the original code points from the first digit to the last, never surrounding labels, punctuation, or whitespace (ADR 0003). The segment text is never rewritten.
- Label boundary: a label must not be preceded or followed by a word character.
- Deduplication: each detector emits at most one finding per
(content_path, start, end). When several bindings support the same span, their evidence is merged and the higher state is kept. - Finding IDs must be unique within a response, for example
au-hpi-i-001andau-vic-vsn-001. The canary detector'sfinding-%03dscheme would collide once two detectors run. - Evidence contains
kind,result,method,version, and an optional label-setreference. It never contains a value, a substring, or an unkeyed hash.
6. HPI-I (validated_structured)
-
Scan every segment as text, including
application/jsonsegments. -
Accept a value in a supported surface form whose normalized form is 16 digits beginning with
800361. -
Luhn: starting from the rightmost digit, double every second digit, subtract 9 from any doubled value above 9, and require the sum of all digits to be divisible by 10. This is equivalent to
inv-hpii-2. -
If the value passes, emit
validation_state: validatedwithshape/supportsandchecksum/supportsevidence. Otherwise emit nothing. In particular, do not emit for:- a Luhn failure, even when labelled;
- prefix
800360(IHI),800362(HPI-O), or any other prefix; - lengths 15 or 17;
- embedded digits or alphanumeric adjacency.
HPI-I never emits
candidateorprobablein v0. Emitting a candidate for a labelled Luhn failure is deferred. -
Optional context evidence: this evidence never changes validation state.
- Proximal label: use the nearest label ending within the 64 code points
before the value, with no digit between the label and the value.
- Supporting labels:
HPI-I(hyphen U+002D, U+2010, or U+2011);HPII; and "Healthcare Provider Identifier<dash>Individual" (case-insensitive; the dash may be U+002D, U+2010, U+2011, U+2013, or U+2014). - Contradicting labels:
IHI,HPI-O,HPIO,HSP-O, andHSPO. These producecontext_label/contradicts. The structure still determines the category.
- Supporting labels:
- Segment URI: if there is no proximal label, the FHIR system URI
http://ns.electronichealth.net.au/id/hi/hpii/1.0anywhere in the segment producescontext_label/supports. - Field key: if the last decoded pointer token normalizes to
hpiiorhealthcareprovideridentifierindividual, and the trimmed segment is exactly the value, addfield_path/supports.
- Proximal label: use the nearest label ending within the 64 code points
before the value, with no digit between the label and the value.
-
validatedmeans the value is validly formed according to a published check digit. It does not mean the identifier was issued, is current, or belongs to the person in the conversation. The HI Service is never queried.
7. VSN (context_bound_structured)
Value
- A supported surface form (contiguous or 3-3-3) whose normalized form is 9 digits.
- Reject
000000000and888888888. - Leading zeros are significant.
- No checksum test is performed. The published check digit's algorithm is unavailable, and v0 must not emulate it.
Text binding
The grammar is LABEL SEP VALUE, with label and value boundaries as defined in
section 5.
- Tier A label:
victorianHWS+studentHWS+number, optionally followed by(VSN)with optional internal HWS. Matching is ASCII case-insensitive. HWS is U+0009, U+0020, U+00A0, or U+202F. - Tier B label: either
VSNin exactly that case, or"vsn"as a double-quoted JSON key in any ASCII case. The quoted form also requires:or U+FF1A inSEP. - SEP:
S1 [WORD S2].S1is 0–8 separator characters;S2is 1–8.WORDis one ofis,number,no., orno(ASCII case-insensitive), and is allowed only whenS1is non-empty.- Separator characters: HWS,
:,=,#,-, U+2013,|,*,",', and U+FF1A. - Line breaks and zero-width characters are not separators. This deliberately excludes non-adjacent text such as "VSN of the student is …".
- Corroboration (tier B text bindings only): look in the same segment for a
whole-word jurisdiction term lying entirely within
[label_start − 200, value_end + 200)code points.- Case-insensitive terms:
Victoria,Victorian. - Exact-case terms:
VIC,VCAA,VRQA.
- Case-insensitive terms:
Field binding
- Split
content_pathon/. - Decode
~1and then~0in each token, and take the last token. An all-digit token is an array index and does not match. - Normalize the key: convert it to ASCII lower case, then delete
_,-,., spaces, and/. If any code point outside[a-z0-9]remains, it does not match. - Classify the key:
victorianstudentnumberis tier A;vsnis tier B. - Trim leading and trailing HWS and line breaks from the segment text. The result must be exactly one VSN surface form. The span excludes the trimmed whitespace.
Evidence-state semantics
| Binding | State | Evidence kinds |
|---|---|---|
| No binding: bare value, jurisdiction term only, TFN/ACN/"student number"/VCAA label, non-adjacent label | no finding | — |
| Tier A text label | probable | shape, issuer_label, jurisdiction (label-intrinsic) |
| Tier B text label + corroboration | probable | shape, issuer_label, jurisdiction (same-segment term) |
| Tier B text label, no corroboration | candidate | shape, issuer_label |
| Tier A field key | probable | shape, field_path, jurisdiction |
| Tier B field key | candidate | shape, field_path |
| Any binding | never validated | Requires a published checksum or an approved registry |
Tier B is candidate because, outside education, "VSN" is an ambiguous acronym
(for example, serial or version numbers). A tenant-approved application schema,
bound through a future snapshot, is the intended route for raising a tier B field
to probable. A detector heuristic is not.
Confidence placeholders in the JSON are uncalibrated. Until OD-019 is decided,
policies must trigger on category and validation_state, not
minimum_confidence. Conformance tests must not assert confidence values.
8. Eligible segments and paths
- Scan every segment regardless of
roleorsource. System prompts, tool results, and model output can all contain identifiers. Policymatchdecides where an action applies. text/plainandapplication/jsonare both scanned as text. Spans index the exact JSON text.- The Portkey adapter currently splits JSON into one
text/plainsegment per string, keyed by its JSON Pointer. Field binding uses those pointers. - When redacting inside an
application/jsonsegment, the replacement must remain a valid JSON string fragment: no",\, or control characters.
- The Portkey adapter currently splits JSON into one
- Labels and values bind only within one segment. Cross-segment and conversation-level binding is a known gap.
- Multiple values per segment are supported. List binding such as
VSNs: a, bis a known gap. This matters because VCAA specifically prohibits VSNs in class lists. - The path is used only for field binding. It is never echoed in evidence beyond
the finding's own
location.content_path.
9. Overlap expectations
- Within the slice, HPI-I and VSN spans cannot overlap because their lengths and
boundary rules differ.
both.pos.disjoint_spansandboth.vsn_label_with_hpi_i_valueprove this. In the second case, a 16-digit HPI-I after a VSN label yields only the HPI-I finding. - Detectors never suppress another detector's findings. With future detectors, the
same span may carry several categories. For example, a generic Luhn or payment
card detector would also match an HPI-I. Each context-bound detector binds only
to its own labels, so identical-span collisions come from validated detectors
without context gates. Any future generic Luhn or payment card detector should
exclude the
80036[0-2]prefixes or rely on deterministic merge rules. - Constraints in the executable slice at review time, verified by reading the
code (all three are fixed; see section 17):
ApplyModificationsrejects overlapping modifications. A redact profile must therefore not include two categories that can produce the same span until a deterministic merge rule exists.- The evaluator runs a detector once per rule and appends every finding. Two rules that use the same detector in one profile duplicate findings, and two redact rules would produce overlapping modifications. Use one rule per detector per profile.
- Finding IDs must be detector-scoped, as described in section 5.
10. Fixtures
The JSON contains 79 cases built from the canonical segment shape. Every wrapped
request validates against evaluation-request.schema.json.
| Group | Positive | Negative | Known gap (gold-sensitive, no v0 finding) |
|---|---|---|---|
| HPI-I | 12 | 12 | 6 |
| VSN | 18 | 16 | 13 |
| Cross-detector | 2 | — | — |
The cases produce 16 HPI-I validated findings, 17 VSN probable findings, and 3
VSN candidate findings. Six cases tagged adr0010_pair reuse a positive VSN
value with no label, a jurisdiction term only, or a TFN, ACN, "student number", or
wrong field label. Each must produce no finding.
Coverage by slice
- Unicode and spacing:
- offsets after a ZWJ emoji sequence;
- CJK text with fullwidth colons;
- U+00A0 separators;
- tabs and multiple spaces in labels;
- Markdown bold and pipe tables;
- quoted JSON keys;
- escaped pointer tokens (
~1); - trimmed field values;
- punctuation adjacent to values.
- Hard negatives:
- Luhn failure;
- IHI, HPI-O, and other
8003prefixes; - card test number
4111…; - lengths 8, 10, 15, and 17;
- embedded digits, alphanumeric adjacency, and decimals;
- five-group and four-group continuations;
- comma grouping;
AVSN/myVSN;- Erlang
{vsn, …}; - VCAA Student Number;
- both sentinels;
- text that is not a value in a VSN field;
- generic
student_numberkeys.
- Known gaps (adversarial/evasion):
- fullwidth and Arabic-Indic digits;
- zero-width characters inside values or after labels;
- combining marks;
- Cyrillic homoglyph
VЅN; - spaced
V S N; - lowercase prose
vsn; - plural
VSNs; - value-before-label;
- line breaks after labels;
- non-adjacent labels;
- unsupported groupings;
- mixed separators;
- cross-segment labels;
- array-element fields.
How the fixtures were checked
Values were chosen by hand. Spans were computed from explicit markers, never by a detector.
- The three synthetic HPI-Is and the HL7 published example pass Luhn; the invalid fixture fails it.
- A throwaway reference reading of sections 5–7 agreed with all 79 expectations, and a mutated expectation was correctly rejected. That script was not committed: it is not a detector, and the conformance guide still calls for an independently authored reference evaluator.
Privacy of fixture values
Fixtures use three HPI-I-valid values and three VSN-shaped values. None is paired with a name, date of birth, school, or practice. Checksum-valid synthetic values are not guaranteed to be unissued. The estimated chance that a given value is real is about 0.1% for HPI-I and below 1% for VSN.
11. Privacy constraints
- Synthetic data only, until privacy approval covers real-traffic observation. Section 26 of the HI Act and s 5.3A.10 of the ETR Act restrict use and disclosure. Legal review must confirm the deploying organisation's and the operator's roles before Groundskeeper processes real traffic containing these identifiers. Self-disclosure by a student (s 5.3A.13) is not a basis for retaining a value.
- Metadata-only telemetry (ADR 0007): counts by category, state, tier, and
rejection reason (for example
checksum_rejectedorsentinel_rejected). Never values, substrings, unkeyed hashes, or path fragments beyond the finding location. Keyed fingerprints are off by default (OD-009). - Errors contain no input. Coverage messages are fixed strings.
- Redaction replacements are fixed category tokens that encode nothing about the value. Reversible tokenisation is excluded (OD-010).
- No remote validation: neither the HI Service nor the Victorian Student Register is queried.
- No external judges receive fixtures or traffic (OD-008).
- No inference is made about people, schools, communities, or Indigeneity. The fixtures contain no names or community material (ADR 0008).
12. Benchmark methodology
- Partitions follow conformance and benchmarking:
- public development: this JSON;
- private fixed holdout: produced by a seeded template generator, authored and held by someone other than the detector implementer;
- incident-derived cases: later, under the separate privacy process.
- Generators combine templates, values, and perturbations, and label from the
template, never from detector output. They cover:
- every surface form, label tier, separator, segment type, and role/source;
- every hard-negative family in section 10;
- known-gap perturbations as a separate evasion slice.
- Benign background: synthetic numeric-heavy text without identifiers, such as logs, CSV and spreadsheets, invoices and orders, code, and phone and banking formats. Reuse public-domain prose only after a licence check. Report findings per million code points. The analytic HPI-I expectation for random digits is about 10⁻⁷ per 16-digit window.
- Metrics:
- exact type-and-span precision, recall, and F1 by category, state, tier, and slice;
- post-redaction leakage (any gold digit remaining) and over-redaction (code points outside gold spans);
- zero rate on bare-value ADR 0010 pairs;
- known-gap recall, reported but not gated;
- latency at p50/p99 per KiB and allocations;
- determinism across repeated runs.
- Statistics:
- Wilson 95% intervals for proportions.
- The rule of three for zero-error claims: zero false positives in n trials bounds the rate below 3/n at 95%.
- McNemar's test and paired bootstrap for version comparisons.
- Reproducibility: pin the generator seed, corpus hash, spec version, detector version, and policy digest. Store raw outputs with values redacted.
13. Provisional non-production gates
Numbers marked † are proposals for OD-004 and OD-019 owners, not decisions.
| Gate | Evidence required | Permits |
|---|---|---|
| G0: implementation merge | 100% of committed fixtures match (category, class, state, span, evidence kind/result multiset)ADR 0010 invariants pass on all outputs (section 14)no values in findings, errors, logs, or metrics (canary test)race and fuzz clean, deterministic outputmanifest declares one class and no permissions | Detector code merged and disabled by default |
| G1: observe | G0holdout precision and recall = 1.0 on supported forms (deterministic rules: any miss is a defect)zero findings on ADR 0010 pairs and hard negativeszero false positives on ≥ 10⁶ benign 16-digit windows (HPI-I) and ≥ 10⁵ benign labelled-negative contexts (VSN)†p99 latency budget characterised† | action: record, required: false, on_error: continue_unjudged on synthetic traffic, or real traffic only after privacy and legal approval of processing roles and metadata telemetry |
| G2: redact | G1zero leakage and zero over-redaction on supported formsno overlapping-modification errors with the profile under testreplacement tokens approved (OD-010)triggers fixed at HPI-I validated and VSN probable | Non-production or limited canary redaction. Best effort against accidental disclosure, explicitly not evasion-resistant |
| G3: block or production enforcement | G2OD-004 thresholds by risk tierOD-019 confidence calibration on approved representative dataOD-005 and OD-006 error posturedecision and measured recall for the evasion slicereal-traffic precision with a lower 95% bound at the agreed tier, from privacy-approved metadata reviewlegal sign-off (HI Act s 26, ETR Act Part 5.3A)rollback drill and owner approvalVSN tier B precision measured before any promotion to probable | Blocking, required: true, or production enforcement |
Observe and redact are permitted only up to G2 and outside production enforcement. Nothing in this slice authorises blocking.
An illustrative policy bundle follows. It validates against
policy-bundle.schema.json. At review time it was not committed because the
detectors did not exist; the implemented equivalent is
policies/examples/au-baseline.yaml (section 17):
bundle_version: "1.0"
name: dev.groundskeeper.examples.au-structured-micro-slice
version: 0.0.1
profiles:
observe:
composition: deny_wins
rules:
- id: observe_au_hpi_i
check: { detector: builtin.pii.au.hpi-i, timeout_ms: 50 }
required: false
on_error: continue_unjudged
trigger: { categories: [privacy.pii.health_id.au.hpi_i], minimum_validation: validated }
action: { type: record }
- id: observe_au_vic_vsn
check: { detector: builtin.pii.au-vic.vsn, timeout_ms: 50 }
required: false
on_error: continue_unjudged
trigger: { categories: [privacy.pii.education_id.au.vic.vsn], minimum_validation: candidate }
action: { type: record }
redact:
composition: deny_wins
rules:
- id: redact_au_hpi_i
check: { detector: builtin.pii.au.hpi-i, timeout_ms: 50 }
required: false
on_error: continue_unjudged
trigger: { categories: [privacy.pii.health_id.au.hpi_i], minimum_validation: validated }
action: { type: redact, replacement: "[AU_HPI_I]" }
- id: redact_au_vic_vsn
check: { detector: builtin.pii.au-vic.vsn, timeout_ms: 50 }
required: false
on_error: continue_unjudged
trigger: { categories: [privacy.pii.education_id.au.vic.vsn], minimum_validation: probable }
action: { type: redact, replacement: "[AU_VIC_VSN]" }14. How the pair proves ADR 0010
| ADR 0010 requirement | Proof in this slice |
|---|---|
| The classes are explicit in manifests and findings | Each detector's manifest declares exactly one class, and every finding carries detector_class. |
| Context-bound detectors emit nothing without a label or field (and jurisdiction) | The adr0010_pair cases, plus bare-value, sentinel, and other-label negatives |
Syntax alone supports candidate; adding context supports probable | VSN tier B (candidate) versus tier A or corroborated (probable) |
validated only from a published checksum or approved lookup | HPI-I validated requires checksum/supports. A Luhn failure produces nothing. VSN is never validated, even with a label. |
| Class does not redefine state, and context does not change a validated state | HPI-I with supporting, contradicting, or no context is always validated. |
| Confidence is calibrated separately per class | Separate placeholders, and a policy rule that forbids confidence triggers until OD-019 |
Inventory include → validated; context_only → context-bound; categories mapped before shipping | au.health.hpi_i (include) and au.education.vic_vsn (context_only), with the mappings in section 4 |
The following invariants must hold for every output, checked mechanically:
validated⇒ somechecksumorreference_matchevidence has resultsupports.context_bound_structured⇒ someissuer_label,context_label, orfield_pathevidence has resultsupports.- VSN
probable⇒ there isjurisdiction/supportsevidence or a tier A binding.
15. Decisions needed
- Pair: approve HPI-I + VSN (recommended), or start with IHI to gain patient value at the cost of higher fixture-collision risk.
- Taxonomy: approve
privacy.pii.health_id.au.hpi_iandprivacy.pii.education_id.au.vic.vsn, including the subdivision level, and extend the initial taxonomy table. - VSN tier B: keep
VSNand"vsn"without corroboration ascandidate(recommended), or treat them asprobableoutright. - Unicode stance: accept ASCII-only v0, with folding and obfuscation measured as known gaps. This must be revisited before G3.
- Privacy and legal (OD-010 and related):
- provisional severities and replacement tokens;
- processing roles under the HI Act and ETR Act before any real traffic;
- whether to request the VSN check-digit algorithm from VCAA as an approved
source. Obtaining it privately would not by itself justify
validated.
- Gates: set the numbers marked † (OD-004 and OD-019).
16. Follow-ups
- The inventory's VSN record says "None published" for the checksum. That remains
accurate, but the record should cite
djsir-vvssc-2027for the check digit's existence and the888888888code. Adding a source changes the inventory invariants enforced byscripts/validate-contracts.sh, so the change is left for a reviewed inventory update. - No
catalog/package was created. ADR 0011 is still Proposed, and no catalogue schema exists to validate against. Once both are approved, move the JSONdefinitionsandcasesintocatalog/packages/groundskeeper.dev/pii-auand convert them to the package test format.
17. Owner decisions and implementation record
Decisions recorded on 3 October 2026
The owner approved the following answers to section 15. They are provisional where marked and do not settle any open decision named below.
| Question | Decision |
|---|---|
| Pair | HPI-I as the validated_structured detector plus the exact-labelled Victorian Student Number as the context_bound_structured detector. |
| Taxonomy | Provisional public categories privacy.pii.health_id.au.hpi_i and privacy.pii.education_id.au.vic.vsn, including the au.vic subdivision level. |
| VSN tier B | The bare VSN acronym or a "vsn" key without Victorian or VCAA context is candidate only. |
| Unicode stance | ASCII digits only in v0. Unicode-digit and format-character evasion is measured and documented as a known gap, and must be revisited before G3. |
| Permitted use | Observe and redact experimental use only, up to and including G2. |
| Enforcement | No production blocking until legal and privacy review and G3. |
| Severities and tokens | The provisional severities (medium, high) and the final redaction-token policy remain governed by OD-010. [AU_HPI_I] and [AU_VIC_VSN] are experimental placeholders. |
Executable-slice invariants fixed before the detectors
The three constraints listed at the end of section 9 no longer apply:
- One execution per detector. The evaluator runs each detector referenced
by an enabled rule exactly once per request and reports its findings once.
Every referencing rule judges the shared output and gets its own coverage
entry. The shared run uses the longest referencing timeout; a rule whose own
timeout_mswas exceeded istimed_outand applies itson_error. - Deterministic redaction merge. Overlapping or identical redactions with
the same replacement merge into their union and carry the sorted union of
finding IDs. Touching spans stay separate. Overlapping redactions with
different replacements fail closed: the decision becomes
block, no modification is returned, and coverage andunjudgedgain a failedevaluation.modificationsentry with reasonconflicting_modifications. The two micro-slice detectors cannot produce overlapping spans, so the example profiles never reach this path. - Response-wide finding IDs. The evaluator assigns
finding-NNNIDs after ordering findings by content path, span, detector ID, and category. IDs are unique across detectors and deterministic for a given request and policy, independent of rule order. Detector-local IDs (au-hpi-i-NNN,au-vic-vsn-NNN) are not exposed.
Section 2's compatibility note is also settled: canonical requests are now
segments-authoritative and payload is rejected, so detectors only ever see
canonical segments.
Implementation
- Detectors:
builtin.pii.au.hpi-iandbuiltin.pii.au-vic.vsnininternal/checks/pii, version0.1.0, implementing sections 5–7 exactly. They are registered as built-ins but run only when the active policy profile references them. The default development policy does not, so they are disabled by default (G0). - Policy:
policies/examples/au-baseline.yamlnow loads in the runtime with anobserveprofile (record; HPI-Ivalidated, VSNcandidate) and aredact-experimentalprofile (HPI-Ivalidated, VSNprobable). Every rule isrequired: false,on_error: continue_unjudged, andoverridable: false, and no rule usesminimum_confidence(OD-019). See policy bundles. - Privacy: detectors never log. Evidence carries only fixed method and version strings. Coverage messages are fixed. Tests serialize complete output and assert that no value or fragment appears in it or in HTTP responses.
Validation
| Check | Where |
|---|---|
All 79 cases match category, class, state, span, and evidence kind/result multiset (16 HPI-I validated, 17 VSN probable, 3 VSN candidate) | internal/checks/pii (detectors) and internal/app (full observe pipeline, request and response schemas) |
| Definitions agree with detector constants: IDs, categories, entity types, classes, severities, prefix, excluded VSN values | internal/checks/pii |
| Section 14 ADR 0010 invariants on every emitted finding, including fuzzed output | internal/checks/pii |
| Case counts, unique IDs, and the 32/28/19 split | scripts/validate-contracts.sh |
| Duplicate-rule, timeout, overlap-merge, conflict, and finding-ID regressions | internal/evaluation |
au-baseline.yaml loads for every profile within the G2 posture; overridable is retained | internal/policy |
| Redaction through canonical and Portkey routes, including field binding | internal/app |
| Fuzzing (determinism, valid spans on ASCII digits, Luhn/sentinel validity, no overlap, invariants), race, and latency | internal/checks/pii, internal/evaluation, internal/app |
Latency was characterised on 64 KiB of adversarial, label- and digit-dense text on a 2-vCPU orb: about 1 ms for HPI-I and 2–3 ms for VSN, linear in input size (about 25 µs and 38 µs per KiB). A regression test fails above 100 ms per 64 KiB. This is a characterisation, not the OD-004 latency SLO.
Known gaps (v0, documented and measured)
- Unicode digits, fullwidth digits, zero-width and other format characters, combining marks, and homoglyph labels evade detection. The 19 known-gap fixtures and 12 generated perturbations all evade v0 (recall 0/19 and 0/12).
- Lowercase prose
vsn, pluralVSNs, list binding, value-before-label, line breaks after labels, non-adjacent labels, cross-segment labels, and array-element fields are not bound. - HPI-I does not emit a candidate for a labelled Luhn failure.
check.configis not passed to built-in detectors in this slice.- Built-in detectors have no manifest file yet; the class is a code constant and is carried on every finding.
- Holdout, benign-background, and real-traffic measurements required by G1 and later gates have not been run.