Reproducibility artifact for “From Risk Register to Runtime Predicate: A Deterministic Method for Compiling AI Governance Assessments into Enforceable Controls”
Abhinandan Gill-Lakhowal, Member, IEEE — Gillian Holdings Incorporated, Calgary, AB, Canada
📊 View the results dashboard (live)
Rendered via GitHub Pages, deployed from this repository’s
mainbranch root — the live page is served directly from the committedresults.htmlwith no separate copy. A single-page, chart-illustrated summary of every measured result below (case hashes, Q1-Q10, injections, determinism, Monte Carlo, L-DREA/ULB reproduction), plus a full campaign history table (every frozen release frompreregister-tier0-v1through the currentv1.1.0) and a Paper 2 v1.2 development-phase section (Surface A, Case D, the 16-row validator matrix, 93-run local + cross-environment determinism, GD/GDmin Monte Carlo regression, compile timing) — explicitly marked as unfrozen, not-yet-reportable evidence, since nopreregister-tier0-v5tag exists yet. Regenerate it any time withmake results/python tools/generate_results_page.py— it is built entirely from the same machine-readable evidence as this README, with no hand-edited numbers.
Current release:
v1.1.0, reportable results inresults/final_v4_1/. Executed after the public prospective scientific freezepreregister-tier0-v4.1, pushed to this repository before the campaign ran and verified from the remote (preregister-tier0-v4.1corrects a manifest-generation provenance defect in the priorpreregister-tier0-v4tag; the two are scientifically byte-identical — seedocs/V4_MANIFEST_DEFECT_REPORT.json).results/final_v3_1/,results/final_v3/,results/final_v2/, andresults/final/hold superseded campaigns, retained unedited for historical comparison, governed by the earlierpreregister-tier0-v3.1/v3/v2.2/v1freezes.
Reportable campaign: results/final_v4_1/
Scientific freeze: preregister-tier0-v4.1
Freeze commit: efe4e165619ecb5d781fb795113f33720794a2e5
Manifest: 461 files, 32 roles, root 0640ad1e7a703879d4b9083a088f5b562b638173590292a2c1aed1625102e0e6
| Case A | Case B v1.1 | |
|---|---|---|
| Bundle SHA-256 | f5cbc3a8016159d2074005fa021bf76ca04fb7aed1408f5ec845418460a43536 |
0d8b602a4c8af888beb27058b7217893eff92d2f9df7f2944d35347c1031cfc1 |
| Q1-Q10 | 10/10 | 10/10 |
| Determinism (paired, 62 runs total) | 1.000 | 1.000 |
| Monte Carlo max FP_heat | 0.321268 (risk R-06) | 0.31798 (risk B-01) |
Case B v1.1 structure: 6 risks, 9 Approved Control Specifications, 9 risk-derived predicates, 3 compiler invariants, 12 predicates total.
Negative fixtures: 19/19 detected (covering the ten canonical queries above; not ten additional queries).
Case B v1.1 injections (13 scenarios): authorization_decision {‘DENY’: 8, ‘HOLD’: 4, ‘PERMIT’: 1}; release_decision {‘ALLOW_RELEASE’: 12, ‘BLOCK_RELEASE’: 1} – release_decision is not a fourth peer authorization outcome.
Tests: 446 passed, 0 failed, 0 skipped.
ieee-check-v4: PASSED (3 stages). Freeze verification: PASS (45 checks, 0 failures).
L-DREA/ULB: original 284,807-row experiment (https://github.com/AGLakhowal/Gamma-Permit-Package.git @ 40fa8f046ad3) reproduced fresh, unmodified: 492 fraud-labelled, 0 false permits, 0 false denials. GC-IR predicate-family correspondence: 4 exact, 3 family, 5 not_established. No new v1.1 corpus replay was executed; no fraud-detection claim is made.
python tools/show_results_v1_1_0.py # current release (this section)
python tools/show_results_v1_1_0.py --json
python tools/show_results.py # historical v1.0.5 / final_v2 campaign
This section is generated by python tools/update_readme_current_release.py; check it without modifying README with python tools/update_readme_current_release.py --check.
Reportable campaign: results/final_v2/
Scientific freeze: preregister-tier0-v2.2
Freeze commit: c44f25d6fdb67e0bc4ac73a6217125dec8da1c0e
Artifact packaging: v1.1.0
| Metric | Case A | Case B |
|---|---|---|
| Bundle SHA-256 | f5cbc3a8016159d2074005fa021bf76ca04fb7aed1408f5ec845418460a43536 |
2850155a2ee7d4c01db4748a891891bae27c48f4c9c2c7eccd30beb7d1aa33ce |
| DC | 1.000 | 1.000 |
| RCY | 0.8125 | 1.000 |
| NDR | 0.1875 | 0.000 |
| OPR | 0.000 | 0.000 |
| ODC | 1.000 | 1.000 |
| PTC | 1.000 | 1.000 |
| CV | 1.000 | 1.000 |
| GD(15) | 3 | 4 |
| GD_min | 3 | 0 |
Determinism: TD = 1.000; 62/62 executions passed (31 per case).
Monte Carlo: K = 250,000 per evaluated risk in Case A; K = 250,000 in Case B. Case A max FP_heat = 0.321268 (MCSE 0.000934); FP_C* = 0 in Case A and 0 in Case B. Observed Case A C* membership changes: 0.
Frozen campaign verification: 280/280 tests; adversarial corpus 62/62; structural checks 26/26; 16 property tests / 1,427 generated Hypothesis examples; 6 clean traceability queries per case, all empty; 18/18 negative controls detected.
Measured cross-platform evidence:
| OS / environment | Architecture | Python | TD | Hashes |
|---|---|---|---|---|
| macOS / local host | arm64 | 3.11.15 | 1.000 | match |
| macOS / determinism-macos-latest-py3.11 | arm64 | 3.11.9 | 1.000 | match |
| macOS / determinism-macos-latest-py3.12 | arm64 | 3.12.10 | 1.000 | match |
| Linux / determinism-ubuntu-latest-py3.11 | x86_64 | 3.11.16 | 1.000 | match |
| Linux / determinism-ubuntu-latest-py3.12 | x86_64 | 3.12.14 | 1.000 | match |
| Windows / determinism-windows-latest-py3.11 | AMD64 | 3.11.9 | 1.000 | match |
| Windows / determinism-windows-latest-py3.12 | AMD64 | 3.12.10 | 1.000 | match |
| Linux / pinned container | aarch64 | 3.11.11 | 1.000 | match |
These results establish properties of the reference governance-to-control compiler and its two pinned case artifacts. They do not establish production detection performance, legal compliance, or superiority over unaided practitioners. RQ5 remains deferred.
make results
Print the complete reportable result set directly from the machine-generated
final_v2 evidence. After make install, use make results; alternatively run
python tools/show_results.py or python tools/show_results.py --json.
This section is generated by make readme-results. Check it without modifying
README with make verify-readme-results or
python tools/update_readme_results.py --check.
Get results in terminal in < 5 minutes:
# 1. Clone and setup (30 seconds)
git clone https://github.com/Sukhmangill977/gc-ir-reference.git
cd gc-ir-reference
make install
# 2. View results (1 second)
make results
python tools/show_results.py
# 3. Run verification (10 seconds)
make test # 320/320 tests
make verify-hashes # Both hashes match
python tools/freeze_check.py --final-v3
# 4. Full campaign (60 seconds)
python run_all.py --final-v3
cat results/final_v3/SUMMARY.md
Docker (if you have it):
docker build -t gc-ir .
docker run gc-ir make results
docker run gc-ir make verify-hashes
Specific operations:
# Compile Case A
python -c "from gcir.caseio import load_case; from gcir.compiler import compile_bundle; \
case = load_case('case_a'); result = compile_bundle(case.compiler_inputs()); \
print(f'Hash: {result.bundle.payload_hash}')"
# Compile Case B
python -c "from gcir.caseio import load_case; from gcir.compiler import compile_bundle; \
case = load_case('case_b'); result = compile_bundle(case.compiler_inputs()); \
print(f'Hash: {result.bundle.payload_hash}')"
# Run Q1-Q10 audit
python -c "from gcir.caseio import load_case; from gcir.compiler import compile_bundle; \
from gcir.audit_queries import run_all_audit_queries; \
case = load_case('case_b'); result = compile_bundle(case.compiler_inputs()); \
queries = run_all_audit_queries(result.bundle); \
for q, (passed, _) in queries.items(): print(f'{q}: PASS' if passed else f'{q}: FAIL')"
# Run 13-injection scenarios
python experiments/case_b_injection_scenarios.py
# Determinism check (62 runs)
python -m experiments.run_determinism --final-v3
The shortest path from a fresh clone to the artifact’s central claims.
git clone https://github.com/Sukhmangill977/gc-ir-reference.git
cd gc-ir-reference
make install # .venv + the pinned dependency set (~30 s)
make results # machine-derived reportable results
make test # current scientific and packaging tests
make verify-hashes # recompile both cases, check the hashes (~2 s)
python tools/freeze_check.py --final-v3 # the frozen metrics, recomputed
python tools/verify_reported_results.py # every paper-facing number (~2 s)
make ieee-check runs that whole sequence plus the traceability and manifest
checks, and returns non-zero if anything disagrees. See
artifact_review/README.md for the reviewer-oriented
artifact guide.
Campaign versus packaging tests. The measured-results section reports the frozen campaign test count.
make testalso runs subsequent reviewer-tooling tests; those additional tests do not change the scientific campaign.
make verify-hashes recompiles Case A and Case B from the committed governance
artifacts and compares the SHA-256 of the RFC 8785 canonical bundle payload
against the reference values committed in cases/*/expected/reference_hashes.json.
If those match on your machine, the compiler is deterministic across your
environment and the one that produced the reference.
Want the whole thing?
python run_all.py --final-v2 # all 13 steps end to end (~60 s)
cat results/final_v2/SUMMARY.md
Everything in that summary is read from a result file a script produced. No number in it is typed by hand.
Enterprise AI governance frameworks end with an approved risk assessment — a document. Deterministic runtime-enforcement architectures begin with an approved predicate set — code. This artifact implements the method the paper proposes for the step between them, and measures the properties the paper claims for it.
The research artifact is the method made executable:
| Component | What it is | Where |
|---|---|---|
| Governance input model | 𝒢 = (M, S, O, R, A) — the five-step assessment, machine-readable |
schemas/assessment.schema.json, src/gcir/models.py |
Ψ_K support tooling |
Validates and assembles signed human selections. Infers nothing from prose. | src/gcir/refinement.py, src/gcir/catalog.py |
| GC-IR | The record family: compiled predicates, non-runtime / accepted / unresolved dispositions | schemas/gcir.schema.json, src/gcir/models.py |
Compiler Φ |
Deterministic compilation to a canonical, hashed, signed, immutable bundle | src/gcir/compiler.py |
| RFC 8785 | JSON Canonicalization Scheme, with ECMAScript number formatting and UTF-16 key ordering | src/gcir/canonicalization.py |
| Authority closure | Every action tuple resolves to S.authority_matrix |
src/gcir/authority.py |
C* coverage |
The consequence-class gate coverage rule CV | src/gcir/coverage.py |
| Lifecycle registry | Retirement, supersession, revocation — signed, outside the payload | src/gcir/lifecycle.py |
| Temporal traceability | The origin chain and all six audit queries | src/gcir/traceability.py, queries/traceability.sql |
| Metrics | DC, RCY, NDR, OPR, ODC, PTC, CV, TD, GD, GD_min | src/gcir/metrics.py |
| Case A | Investment research agent — synthetic, 16 register rows | cases/case_a/ |
| Case B | Transaction authorization agent — forensic reconstruction, 6 rows | cases/case_b/ |
Not a production system, not an AI agent, not a runtime enforcement engine, and not a user interface. The enforcement layer belongs to the cited prior work and is not restated here. This artifact stops at the compiled bundle.
The paper’s own boundary governs. Applied to this artifact:
Claimed and measured here. Total disposition; deterministic compilation after
approval; authority closure; C* coverage with the Proposition 1 and 2 premises
instantiated on the pinned register; measured divergence from the declared
heat-map comparator; origin-closed, temporally valid traceability; fail-closed
unknown handling on mandatory gates; orphan-control impossibility within
Φ-produced bundles.
Not claimed, and not measurable from anything in this repository.
SNR and DF are reported as
DEFERRED, never as numbers.TD = 1.000 (62/62). That is a wide tested
set, but a finite matrix is still not the set of all environments. See
results/final_v2/CI_STATUS.md.docs/RESULT_INTERPRETATION.md states, metric by metric, what each number means
and what it does not.
Reading the frozen documents. Several files under
docs/are part of the preregistration record and are covered by the freeze manifest. They still point atresults/final/(the v1 path) in places, and they have deliberately not been updated — rewriting a preregistered document after seeing the results would destroy the evidence the freeze exists to provide.docs/FROZEN_DOCS_READING_NOTE.mdsays how to read them; it is not frozen.
M, S, O, R, A approved governance assessment (Section III)
│
│ K ── approved, versioned Control Derivation Catalog
▼
┌──────────────────────────────────────────────────────────┐
│ Ψ_K governed semantic refinement -- A RELATION │
│ closed into a mapping only by the signed │
│ judgment record J. Human judgment happens HERE, │
│ once, and is signed. │
└──────────────────────────────────────────────────────────┘
│ (D, Δ) ∈ Ψ_K(𝒢); Ψ_K(𝒢, J) → (D, Δ)
▼
┌──────────────────────────────────────────────────────────┐
│ Φ deterministic compiler │
│ exact catalog lookup · authority closure · │
│ C* coverage · mandatory unknown-failure · │
│ RFC 8785 · SHA-256 · no clock, no RNG, no LLM │
└──────────────────────────────────────────────────────────┘
│
▼
(P, G, E, B) predicates · gate map · escalation map · signed immutable bundle
│
├── lifecycle registry REG (separately signed; NEVER in the payload)
└── receipts ValidAt(t, b, REG) at decision time
The refinement boundary is the point of the design: human semantic judgment is
exercised once, under an approved catalog, and recorded in a signed judgment
record. Everything to the right of it is a function of signed inputs. Determinism
is claimed for Φ, never for the interpretation of unconstrained prose.
tests/adversarial/test_no_inference.py asserts this statically over the shipped
source: the compiler path imports no RNG, no similarity library, no model library,
and reads no clock.
gc-ir-reference/
├── src/gcir/ the implementation (16 modules, no framework)
├── schemas/ 13 JSON Schema (draft 2020-12) documents
├── cases/case_a/ synthetic investment-research case
│ ├── inputs/ M, S, O, R, A + catalog + C* profile + INV + thresholds
│ ├── judgment/ the signed judgment record J
│ ├── dispositions/ Δ
│ ├── acs/ D -- the Approved Control Specifications
│ ├── lifecycle/ registry, receipts, actuations + negative/ fixtures
│ └── expected/ committed reference canonical payload hash
├── cases/case_b/ forensic-reconstruction transaction-authorization case
├── catalog/ the approved catalogs, published at the paths Appendix C names
├── invariants/ the approved invariant registers
├── queries/ traceability.sql -- the six audit queries
├── tests/ unit · properties · adversarial · integration
├── experiments/ every measurement, plus reproduce_all
├── results/development/ exploratory results -- NOT reportable
├── results/final_v2/ ** THE REPORTABLE CAMPAIGN ** (freeze preregister-tier0-v2.2)
├── results/final/ the SUPERSEDED v1 campaign -- retained for provenance only
├── results/V1_V2_COMPARISON.md every difference between the two, with its cause
├── artifact_review/ IEEE artifact-review package: reviewer README, the
│ paper-to-result map, data inventory, self-review
├── preregistration/ TIER0_FREEZE_V2.md + FREEZE_MANIFEST_V2.sha256 (governing);
│ TIER0_FREEZE.md + FREEZE_MANIFEST.sha256 (v1, historical);
│ RQ5_DEFERRED_PROTOCOL.md, HELD_OUT_REGISTER.md
├── paper_update/ measured results, the placeholder replacement tables, and
│ the manuscript-finalization audits
├── docs/ requirements extraction, claim matrix, provenance, interpretation
├── tools/ case-fixture generators, freeze_check, the result map and
│ the reported-result verifier
└── keys/ research signing keys -- TEST ONLY / NOT FOR PRODUCTION
Python 3.11 or 3.12. No other runtime dependency. Four packages
(jsonschema, referencing, cryptography, numpy) plus pytest and
hypothesis for the test suites, all pinned in requirements.lock.
make install # or, with an explicit interpreter:
make install PYTHON=python3.11
make install checks the interpreter first and stops with a clear message if it
is older than 3.11 — without that guard, the first symptom is pip failing to
resolve a transitive dependency, and that error never mentions the Python
version.
make docker-build # base image pinned by digest
make docker-reproduce # docker run --rm gcir make reproduce
The container fixes LANG, LC_ALL, TZ and PYTHONHASHSEED so the baseline
environment is declared rather than inherited — and the determinism experiment
then deliberately varies all four, so the pinning is a stated starting point, not a
way of avoiding the question.
make test # all four suites
make ieee-check # the full reviewer check (~2 min)
.venv/bin/python -m pytest tests/properties -q --hypothesis-show-statistics
make reproduce # 11 steps -> results/development/
make reproduce-final-v2 # the REPORTABLE campaign -> results/final_v2/
make reproduce-final # the SUPERSEDED v1 campaign -> results/final/
# individual experiments (add --final-v2 to write into results/final_v2/)
.venv/bin/python -m experiments.run_case --case case_a
.venv/bin/python -m experiments.run_determinism --runs-per-case 31
.venv/bin/python -m experiments.run_gate_divergence
.venv/bin/python -m experiments.run_monte_carlo --draws 250000
.venv/bin/python -m experiments.run_traceability
.venv/bin/python -m experiments.run_adversarial
.venv/bin/python -m experiments.run_metrics
make reproduce-final-v2 overwrites the reportable results. It exists so the
frozen campaign can be re-executed and compared, but a reviewer verifying the
published numbers should use python tools/verify_reported_results.py or
make ieee-check, which read the committed evidence and write nothing into
results/final_v2/.
make verify-hashes # against the committed references
make verify-manifest # the manifest is current
shasum -a 256 -c <(awk '!/^#/ && NF {print $1 " " $3}' MANIFEST.sha256)
Every hash in MANIFEST.sha256 is computed from the file on disk by
experiments/make_manifest.py. Each line carries the Appendix C role alongside the
path.
make verify-manifest regenerates the manifest and diffs it against the committed
one, excluding two rows that necessarily change: results/development/ (which
make reproduce rewrites by design) and MANIFEST.json itself. MANIFEST.json
embeds every file’s hash including its own from the previous generation, so it
never reaches a fixpoint — a plain git diff --exit-code MANIFEST.sha256 after
regenerating would therefore always report a difference and tell you nothing. The
filtered comparison is what CI runs, and it is the meaningful check: every
released path must match exactly.
| File | Purpose | Changes when |
|---|---|---|
MANIFEST.sha256 / .json |
Inventories the current repository / release state. 304 files, 30 roles. | Any file is added or edited. Regenerate with make manifest. |
preregistration/FREEZE_MANIFEST_V2.sha256 |
Proves the frozen scientific experiment: the 133 files covered by preregister-tier0-v2.2. |
Never. Regenerating it would destroy the evidence it exists to provide. |
# the register, its dispositions and its gates
python -c "import json;d=json.load(open('cases/case_a/inputs/assessment.json'));
[print(r['risk_id'], '|', r['event'][:70]) for r in d['risk_register']]"
jq '.records[] | {risk_id, status, reason_code}' cases/case_a/dispositions/dispositions.json
jq '.predicates[] | {gcir_id, gate_type, gate_source, mandatory_role}' results/development/case_a/gcir_records.json
jq '.c_star_coverage' results/development/case_a/coverage_matrix.json
The canonical bytes that were hashed are written verbatim to
results/*/case_*/canonical_payload.json, so you can hash them yourself:
shasum -a 256 results/development/case_a/canonical_payload.json
cat results/development/case_a/payload_hash.txt
Every result file carries an environment block: git commit, git tag, whether the
working tree was clean, Python version, platform, and every dependency version.
phase says development or final. A number can always be traced back to the
state that produced it.
results/development/ holds exploratory numbers from while the implementation was
being built. They are not reportable, and they are committed rather than
deleted so the development history the freeze separates from is visible.
results/final_v2/ holds the reportable campaign. Its freeze
(preregistration/TIER0_FREEZE_V2.md, tag preregister-tier0-v2.2, commit
c44f25d6fdb67e0bc4ac73a6217125dec8da1c0e) was pushed to this repository and
verified from the remote before the campaign executed. Per Section XI-I: “The
internal selection of frozen elements is not a freeze — the public timestamped
commitment is.”
results/final/ holds the superseded v1 campaign. It is retained unedited,
for provenance, and is not reportable: its freeze tag preregister-tier0-v1
existed only locally when that campaign ran, and was pushed afterwards. A later
push cannot turn a completed experiment into a prospectively public preregistered
one, so v1 was superseded rather than relabelled — its metadata was not
edited and public_commitment_discharged was not flipped retroactively.
results/V1_V2_COMPARISON.md compares the two value by value. Every substantive
measured value is identical across the two independently executed campaigns; what
changed is the determinism run count (30 → 31 per case), the adversarial corpus
size (59 → 62) and the addition of the Case B injection scenarios — all deliberate
scope increases made before the v2 freeze.
Full detail: docs/REPRODUCIBILITY.md and docs/EXPERIMENT_PROTOCOL.md.
The comparative expert study is preregistered and not executed. Its protocol is
frozen in preregistration/RQ5_DEFERRED_PROTOCOL.md and hash-committed, so it is
bound to be run as written rather than merely promised.
No adjudication panel has been convened. No practitioner has been recruited. No
participant data exists. SNR and DF are reported as DEFERRED. No script in
this repository generates, simulates or approximates human study data.
The held-out expert-study register is withheld until study close, and
preregistration/HELD_OUT_REGISTER.md records that its hash commitment is openly
outstanding rather than committing a hash of a placeholder.
Beyond the claim boundary above, and beyond the manuscript’s Section XII:
docs/FIXTURE_PROVENANCE.md lists every one with the basis on which it was chosen.GD_min is partly a function of fixture ratings. Both GD sums run over all
sixteen Case A rows. The three non-runtime ratings are documented fixtures —
now published in the manuscript as R-14 = 12, R-15 = 6, R-16 = 8 — and a full
sweep over every plausible value shows GD_min would range over 2 to 5. The
artifact reports that sweep alongside the measured value (FP-014). Neither
proposition premise depends on those three rows.provenance_warning, and in paper_update/MEASURED_RESULTS_V2.md (FP-020). The
submitted manuscript states this in the abstract, §XI-C, §XI-G and §XII.TD = 1.000 (62/62) reproduces on
eight environments. That is not platform independence, and the artifact never
claims it is.See CITATION.cff. The artifact is released under MIT (LICENSE), matching the
precedent named in the manuscript’s Appendix C.
SECURITY.md. In short: this is a research artifact, the committed keys are test
fixtures, and nothing here should be deployed.