This page is the evidence dossier: the corpus, one full chain, the register, the records and the reproducers, each with the file behind it. The narrative account of how the two misses happened is the jsonparser postmortem.
Fast path
The accounting
123
requirements captured7 stakeholder promises and 116 system clauses, one YAML file each, in specs/.
28
approved The other 95 are candidates at status: review. Only an approved requirement is judged against code.
6
defects the review found Six of the eight records below. Outside contributors reported the other two, and the changelog credits them by name. 6 + 2 = 8.
2
defects published as misses Those same two. Both in Set(), both past the gate, both written up in the public postmortem. Section 05 states who reported them and where our own record disagrees with the changelog.
known-issue records on masterKI-1 to KI-4 in proof/known-issues/, every one fixed. The register holds problems that stayed open, so it is not a tally of the eight: three of the eight defect files name no known issue, each having been found and fixed in the same pass. Section 04 maps the rest. The seeded demo branch carries a longer list, and the portal counts that one.
PUBLIC AUDIT EVIDENCE Counted on the master branch of buger/jsonparser on 30 August 2026. Each row is a directory listing or a status field, so you can count it yourself: grep -h '^status:' specs/*/requirements/*.yaml | sort | uniq -c prints the first two rows. The portal numbers further down this page count the seeded demo branch instead, and they are labelled where they appear.
Two projects, one name
Project
jsonparser
PUBLIC AUDIT EVIDENCE
buger/jsonparser, branch master. The library people depend on. The requirements, the eight defect records, the reproducers and the postmortem live here.
Every count in the strip above is read off this branch. KI-1 to KI-4 were real defects in this code and all four are fixed.
Project
jsonparser-demo
SEEDED PRODUCT DEMO
probelabs/jsonparser, branch proof-demo. A fork with defects put there on purpose, so the portal has live failures to show.
Every portal screenshot and every portal link on this page opens this branch. Its findings from KI-5 up are seeded entries, and none of them is a defect in the library. The portal still serves it at the path /projects/jsonparser; this page calls it jsonparser-demo so the two never share a name.
01 · The dashboard
The live project dashboard.
The subject is jsonparser, a decade-old Go library maintained by Proof’s founder. It went first on purpose, as code we could not hide from. The dashboard below is jsonparser-demo, the seeded branch: it is public, it is served from the same portal a client gets, and we do not edit what it reports. The verification panel reads Needs attention because that is what the run said.
SEEDED PRODUCT DEMOjsonparser-demo · the figure below and every portal link in this section open the seeded branch.
portal.reqproof.com/projects/jsonparser
SEEDED PRODUCT DEMOjsonparser-demo · branch proof-demo on the probelabs/jsonparser fork. The 10 open findings in this shot are seeded entries, and none of them is a defect in the library. Read the labels first.
PUBLIC AUDIT EVIDENCEjsonparser · the four counts below come from master. The shot above came from the seeded branch.
123 requirements28 approved4 issue records, every one fixed2 misses published
The audit ran in July 2026. All four counts are read off master in buger/jsonparser and were last counted on 30 August 2026, which is why they differ from the seeded branch in the shot above. Each count is a directory or a document you can count yourself; the accounting strip names every population and section 04 reconciles the defect numbers against the files.
Overview
The latest run, the commit it ran on, and whether verification is complete.
Findings
The issue catalogue: known issues, problem reports, accepted risks and failing checks, by kind.
Requirements
Every requirement with its specification, rationale, obligations, evidence and trace links.
Audit checks
The checks behind the gate, and which of them are passing on this commit.
Map
The intent graph: requirements, code, tests and hazards, and the edges between them.
Timeline and activity
What changed, when, and which evidence had to run again because of it.
The behavior of the library was formalized into 123 requirements: 7 stakeholder promises and 116 system clauses, plain YAML in the tree. A person who owns the code approves each sentence, and only an approved requirement is judged against. On 30 August 2026, 28 carried status: approved and the other 95 were still candidates at status: review. Each file says which.
SEEDED PRODUCT DEMOjsonparser-demo · the shot below is the portal reading the seeded branch. The requirement corpus is the same 123 files that master carries.
SEEDED PRODUCT DEMOjsonparser-demo · the same run as the dashboard above. The corpus it lists, counted by the product itself: 123 requirements, of which 7 are stakeholder and 116 are system, with no software level in this project. The status column is mixed on purpose: the top stakeholder row reads review, the state section 03 records for STK-REQ-005.
Requirements
7 stakeholder promises and 116 system clauses. Every one carries its own status field, and only an approved requirement is judged against.
Formal specifications
The system clauses carry machine-checkable specifications: FRETish, compiled to temporal logic.
Annotations
All 279 functions declare the requirements they serve, in the source itself, so the trace moves when the code moves.
Obligations
Each requirement lists what must hold for it to count as verified, with its worst case beside it.
Evidence manifests
The runs that satisfy each obligation, in proof/evidence/. An unmet obligation shows up as a hole in the file.
Condition coverage
MC/DC measured at 100% of decisions and 100% of conditions on the audited code. Section 05 is where that number stops being enough.
The gate
The strict audit gate on every commit: zero errors, zero warnings. It reruns without us.
One requirement, and every artifact attached to it. Each step below is a file in the public repository. Open them in order and you have checked the chain yourself, without asking us anything.
PUBLIC AUDIT EVIDENCEjsonparser · every step below is a file on master, linked from the step that names it.
The finding, walked in time
01requirement
SYS-REQ-009approved
Set() replaces the addressed value, creates a type-consistent path, or returns KeyPathNotFoundError. A person who owns the code approved that sentence before any code was judged against it.
An array-index path component under an object parent produced malformed JSON output, and Set() returned it with a nil error. The caller had no signal that the bytes could not be parsed again.
One executable test, pinning the failure while it was live: it asserted that the output was not valid JSON. The file carries // Verifies: SYS-REQ-009 and // Reproduces: KI-3 on one screen, so it says which promise it proves and which failure it pins.
The record names the code that carried it and dates it to the library's first release, so every revision before the fix is affected. The requirement's own history stamps the window: verification failing on 26 July 2026, passing again the next morning.
Set() now replaces a mismatched container with the type the path expects, so every non-erroring call returns valid JSON. The defect record names the root cause, the obligation it added, and the regression test.
The same test as step 03, still in the suite, flipped at the fix: it now asserts that every cross-type call returns valid JSON. The obligations on the requirement run against it again.
The same sentence as step 01, re-approved by the engineer who owns the code once the hardening was attached, with the defect named in the record as the reason for the re-approval.
Fig. 01 · PUBLIC AUDIT EVIDENCE Seven steps, seven records, and each one is a file in the public repository on master. The requirement that opens the chain is the requirement that closes it.
The same chain, file by file
01
Stakeholder promiseSTK-REQ-005status: review
Users update or delete addressed JSON values through the experimental mutation helpers, with deterministic edge-case behavior.
Read the file and the third line says status: review. The promise at the top of this chain is still a candidate, so nothing is judged against it yet, and we left it in view. The approved sentence is the next step, and that is where the obligations and the evidence attach.
Set must update the addressed JSON value without corrupting unrelated structure.
Approved means a person who owns the code approved the requirement. Until a requirement is approved it is a candidate, and nothing is judged against it. The line above is our summary of it; the approved text is the description field in SYS-REQ-009.req.yaml, and it is longer and more exact than a card can carry. The file names the reviewer and the role, and it records that it satisfies the promise in step 01.
Boundary, idempotency, malformed input, nested mutation. What must hold for the requirement to count as verified, and which evidence proves each one.
The obligations are where a requirement stops being prose. Each one is listed in the requirement file next to its worst case, and the manifests that satisfy it live beside them, so an unmet obligation shows up as a hole in the file.
The comment directly above func Set lists every requirement that function carries, SYS-REQ-009 first.
The annotation lives in the source, so it moves when the code moves. Follow the link and the highlighted lines are the annotation and the function it sits on.
One test file carries // Verifies: SYS-REQ-009 and // Reproduces: KI-3 (fixed), on one screen.
This is the join that makes the rest checkable: the same file says which promise it proves and which failure it pins. Run it with go test -run TestSetArrayIndexUnderObjectMalformedJSON_KI3.
The register entry: severity with its basis, the evidence, and the review dates.
A known issue is an unresolved problem. It stays a known issue until the closure is verified, and the register says which state it is in. This one now reads status: fixed.
Defect recordDEFECT-260726-MFPAcovered by requirement
The history that stays after the fix: root cause named, hardening recorded, reproducer pinned in CI.
The requirement that opened the chain is the requirement that closes it, proven again on the fixed code. This record strengthens SYS-REQ-009, which is step 02.
Nothing in that chain is a screenshot of a screen that does not exist. Every step is a file in a public repository, and the links above go to the files themselves.
04 · The findings
Six defects the review found.
The count is worth stating carefully, because the artifacts are public and you can count them yourself. proof/problem-reports/ on master holds eight defect files, every one fixed. Two of the eight were reported by outside contributors and credited by name in the changelog, which leaves six the review found itself. Those two outside reports are the two misses in section 05.
No reproducer, no finding.
A finding you cannot re-run is an opinion with formatting. The reproducer is what gives a finding its authority. Every entry below is dated, publishes its own triage boundary, and names the person who validated it or says why the name is withheld.
PUBLIC AUDIT EVIDENCEjsonparser · the four rows are the known-issue files on master. The seeded demo branch is not counted here.
The register, read off master
6
found by the review
2
reported outside, credited
8
defect files on master
4
known-issue records shown in this register
Fig. 02 · PUBLIC AUDIT EVIDENCE The register lists known issues; the full defect
history sits beside them in proof/problem-reports/, and the two outside reports are credited by name in the CHANGELOG — they are the two misses in section 05. KI-2 and KI-4 were fixed later, in v1.6.0.
FindingWhat was wrongResult
KI-1
An empty key path component panicked in the key search where an error was owed.
Four issue records on the project's master branch, every one of them status: fixed, every one of them carrying the command that reproduces it. Four records and eight defect files count different things, and the register is the smaller of the two because a defect found and fixed in one pass never becomes a known issue: DEFECT-260726-3PSJ, DEFECT-260727-ARR1 and DEFECT-260727-SNGT name none. KI-1's only defect file is DEFECT-260726-QS2V, which is one of the two credited outside rather than one of the six. The wider defect history sits beside them in proof/problem-reports/.
One resolved defect record, in full.
A resolved defect record is what stays after a fix is verified. This is DEFECT-260726-MFPA, the record for KI-3, read off the public register.
PUBLIC AUDIT EVIDENCEjsonparser · every field below is transcribed from DEFECT-260726-MFPA.yaml on master.
DEFECT-260726-MFPA · KI-3 · Set() / array-index path under an object parent
Fixed
Expected
Set writes the value at the addressed path.
Observed
Malformed JSON output on array-index paths under object parents.
Reproducer
set_spec_test.go· // Reproduces: KI-3 (fixed) ·go test -run TestSetArrayIndexUnderObjectMalformedJSON_KI3
While the bug was live this test asserted the bug: it pinned the output as not valid JSON. It was flipped at the fix and now asserts the opposite, so a regression trips it either way. It was never red and then green, and saying so would have been the easier story.
Severity
high · basis: reproducer. Our assessment, weighted by reachability and impact, offered as a starting point for the maintainers' triage. No CVSS determination is claimed.
Fixed and pinned. The reproducer stays in CI as a regression test.
Originating issue
Where the problem came in, including when a user reported it.
Defect record
The evidence-bearing history after the fix is verified: root cause named, hardening recorded.
Closure evidence
The test that pins the failure, and the named revision it was run on. Some pin it by failing until the fix lands. Some pin it by asserting the broken behavior while it is live and getting flipped at the fix. The record says which.
Class-closure status
Whether the whole failure mode is closed, or only this instance of it. The two are never merged into one count.
Fixing change
The change that landed upstream, and the release that carries it.
Affected requirements
Which promises this touched, so the evidence they depend on runs again.
One reproducer settles the instance. Closing the whole defect class takes broader evidence, and the record states which of the two it claims.
The postmortem on this project is called Two Bugs That Escaped L3 Strict Proof Review, and two is the honest number. Both misses are in Set(). The affected code carried 100% MC/DC at the time, which means every condition in the decision logic we checked was exercised. It does not mean the behavior was correct.
PUBLIC AUDIT EVIDENCEjsonparser · both misses are defect files on master, and the postmortem that names them is on master too.
Ask Set to write at the path "a" then "", and it panics. The empty path component is the same failure class a hazard sweep had already closed. The sweep found seven sites, fixed all seven and reported clean. The eighth was written keys[depth:][0][0]; the pattern the sweep matched on was keys[i][0], and it walked past.
This escape has no problem report of its own on master. What it has is the record of the sweep that missed it: DEFECT-260726-QS2V closes the other seven sites and signs off sibling_sweep: result: clean — “No further live instances of the unguarded-index anti-pattern remain in parser.go.” The eighth site falsified that sentence on the same branch that wrote it. Read the two together: the sweep record first, then section 3 of the postmortem, which is the only account of the site the sweep walked past.
Both problem reports open with source: type: audit_finding. The project's changelog credits an outside reporter for each of the same two fixes, by name, and lists both names again in that release's acknowledgments. Two files in one repository disagree about where these came in, and the public record does not settle it. What is not in tension: the gate stopped neither defect, and a credit like that stands.
Our own ledger promises to record when a user reported a problem, and on these two entries it does not. That is a third gap, and we state it here.
Both defects date to the library's inception, years before this work, so writing them was not the failure. Certifying around them was. Both sat inside the declared scope with evidence attached, so nothing about the boundary excuses either one.
The changelog names three more escapes, fixed in v1.3.1 with no postmortem of their own. That is a gap in the register rather than an absence of misses, and it is recorded here for the same reason the other two are.
What we published
The root-cause analysis, blameless, specific and public, on the project's master branch, next to the finding and the fix, where you can re-run both. It runs to six sections including a remediation table, and the last of them is titled What proof did right, because the specified hazards were caught precisely for being specified. It is not signed. Its author line reads proof-gap review, and what you check it against is the reproducers.
An auditor that only shows you its wins is asking for faith. Open the postmortem and its own first line will tell you the count is two. The narrative account of both escapes walks how each one got through.
Two requirements that did not exist before, both now approved, and three instruments that check them. Every row below is a file on master, and every one of them runs on each commit.
PUBLIC AUDIT EVIDENCEjsonparser · five files on master, each linked from its row.
SYS-REQ-110
What Set owes an array index past the end of the array, for every element type, including the ones the old code skipped. SYS-REQ-110.req.yaml
SYS-REQ-111
The empty path component is a defined input on every entry point, and it must never panic. SYS-REQ-111.req.yaml
Reference oracle
Compares output against the standard library, so a plausible-looking wrong answer still fails. reference_oracle_test.go
Path fuzzer
Explores the key path as well as the bytes, which is where both escapes lived. path_fuzz_test.go
Signal rule
Flags the unguarded dereference in every spelling, including the one the sweep walked past. Its file header says so. unchecked-caller-slice-deref.yaml
A requirement with nothing checking it is a sentence, which is why each of the two arrived with machinery attached. One passing reproducer proves an instance dead; closing a whole class takes broader evidence, and each record states which of the two it claims.
07 · The receipts
Rerun everything yourself.
Everything above resolves to a file in a public repository. Here are the six you can open: the repository, the requirements, the live graph, one reproducer, the register and the postmortem. Five are files on master under the project's own licence. The sixth is the seeded demo, badged as such below.
portal.reqproof.com — the dashboard, the findings, the requirements and the graph. No account, no sales step. Its open entries are seeded, and none of them is a defect in the library. Read the labels first.
set_spec_test.go — what it verifies and what it reproduces, on one screen. Clone the repository and run go test -run TestSetArrayIndexUnderObjectMalformedJSON_KI3.