{"schema":"VGS-CHANGELOG-v1","title":"VeriSigil Engineering Changelog","philosophy":"Every finding published — fixed or not. Silent patching undermines the trust that the governance layer is supposed to build.","entries":[{"date":"2026-08-07","version":"0.9.x","type":"VALIDATION CLOSED","id":"RUN-3-CLOSED","title":"CLARA Run 3 cycle formally closed — all findings independently confirmed by Alkama Eqbal","confirmed_by":"Alkama Eqbal, independent reviewer","findings_closed":["CV-003 (ESCALATE fix)","CHG-010 (CV-005 state hash)","CHG-011 (verify/kit 500)"],"alkama_note":"A signature updated during the no-auth refactor while the body still called the old auth helper is exactly the class of bug that only shows up from the outside, because internally the code still reads correctly. That is the argument for having someone hit the public surface with no key on every deploy, not just at the end of a cycle.","engineering_action":"test_public_endpoints.py added as permanent regression gate — 28 tests, 7 sections, runs on every deploy via GitHub Actions"},{"date":"2026-08-06","version":"0.9.x","type":"BUG FIX","id":"CHG-011","title":"verify/kit regression — 500 Internal Server Error after no-auth change","found_by":"Alkama Eqbal, post-deploy re-check (2026-08-06)","description":"GET /v1/verify/kit returned 500 on all calls (with and without API key) after the no-auth change. Root cause: function signature was changed to remove auth parameters but the body still called require_api_key(x_api_key, authorization) — undefined variables in scope causing NameError at runtime. This is a regression introduced by CHG-006 (auth removal).","fix":"Removed stale require_api_key call from verify_kit function body.","confirmed_closed":"CONFIRMED 2026-08-07 — Alkama Eqbal final pass: verify/kit returns 200 with full verification table no key. Conformance 200 public. CHG-011 readable in changelog no key. Run 3 cycle formally closed.","alkama_note":"A signature updated during the no-auth refactor while the body still called the old auth helper is exactly the class of bug that only shows up from the outside. This is the argument for hitting the public surface with no key on every deploy."},{"date":"2026-08-06","version":"0.9.x","type":"BUG FIX","id":"CHG-010","title":"CV-005: state_verify read wrong field name — always compared against empty hash","found_by":"Alkama Eqbal, CLARA Run 3 CV-005 analysis (2026-08-06)","description":"POST /v1/state/verify read 'current_state_fields' but callers naturally send 'state_fields' (same field name as POST /v1/state/commit). This caused current_fields to always be {} and current_hash to always equal sha256('{}') = 44136fa... — making every verify call return STATE_CHANGED regardless of actual state. Alkama identified this from the state_hash in the commit response: 44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a is sha256 of empty JSON.","fix":"state_verify now accepts both 'state_fields' and 'current_state_fields'. Commit and verify use the same field name naturally.","confirmed_closed":"Pending Alkama re-check of CV-005.","alkama_credit":"Finding correctly attributed to Alkama Eqbal — precise root cause analysis from hash value alone."},{"date":"2026-08-06","version":"0.9.x","type":"BUG FIX","id":"CHG-010","title":"CV-005: state_verify read wrong field name — always compared against empty hash","found_by":"Alkama Eqbal, CLARA Run 3 CV-005 analysis (2026-08-06)","description":"state_verify read current_state_fields but callers send state_fields. Empty dict always. Hash always 44136fa. Every verify returned STATE_CHANGED regardless of actual state.","fix":"state_verify now accepts state_fields OR current_state_fields.","confirmed_closed":"CONFIRMED 2026-08-07 — Alkama Eqbal final pass: commit then verify unchanged returns FRESH with PROCEED. Verify modified returns STATE_CHANGED with HALT. Both directions match expected behaviour."},{"date":"2026-08-05","version":"0.8.x","type":"SECURITY FIX","id":"CHG-008","title":"Server-side tier validation — self-declared tier gap closed","found_by":"SDK integration testing","description":"A caller could self-declare ADVISORY on any action including high-value transfers, bypassing the multi-party requirement for CRITICAL/EMERGENCY tier.","fix":"HIGH_RISK_ACTIONS set defined server-side. If action is known high-risk but declared ADVISORY, effective tier is upgraded and mismatch flagged.","open_gap":"Server-side tier computation validates declared tier but does not independently classify based on payload contents (e.g. amount). Full payload-aware classification is a future enhancement."},{"date":"2026-08-05","version":"0.8.x","type":"FIX","id":"CHG-007","title":"CV-003: HIGH irreversible + human present → ESCALATE not ALLOW","found_by":"Alkama Eqbal, CLARA Run 3 (2026-08-04)","description":"HIGH consequence, irreversible, human_present=true returned ALLOW. Expected ESCALATE. Engine treated human presence as reason to bypass escalation rather than route to it.","fix":"Signal 3b HIGH_IRREVERSIBLE_ESCALATE added to _run_intercept. Human present = someone to escalate to, not reason to bypass.","confirmed_closed":"Pending Alkama Run 3 re-validation of CV-003."},{"date":"2026-08-05","version":"0.8.x","type":"FIX","id":"CHG-006","title":"Auth discrepancy: verify/kit and verify/conformance returned 401","found_by":"Alkama Eqbal, CLARA Run 3 (2026-08-04)","description":"Endpoints documented as public (no auth) required sandbox key.","fix":"require_api_key removed from both endpoints.","confirmed_closed":"Yes — confirmed public in prior deploy."},{"date":"2026-08-05","version":"0.8.x","type":"UPGRADE","id":"CHG-005","title":"SQLite nonce ledger replaces in-memory set","found_by":"Internal review — consequence-custody-spec.md analysis","description":"In-memory set() lost all nonces on process restart. Restart attack made replay prevention fail silently.","fix":"SQLite with PRAGMA journal_mode=WAL and UNIQUE constraint. Survives restarts. Atomic under concurrency.","confirmed_closed":"Yes — deployed 2026-08-05."},{"date":"2026-07-30","version":"0.7.x","type":"FIX","id":"CHG-004","title":"F-5: payload_hash not echoed in intercept response","found_by":"Alkama Eqbal, CLARA Run 2 (2026-07-28)","description":"Canonical reconstruction failed for third-party verifiers because payload_hash was missing from the intercept response.","fix":"payload_hash now echoed in all intercept responses.","confirmed_closed":"Yes — confirmed by Run 3: 'intercept responses now include payload_hash'."},{"date":"2026-07-30","version":"0.7.x","type":"FIX","id":"CHG-003","title":"F-4: Signing key was ephemeral before 30 Jul 2026","found_by":"Alkama Eqbal, CLARA Run 2","description":"Signing key regenerated on each deploy. Receipts before 30 Jul 2026 are not retroactively verifiable.","fix":"SHA256(SIGN_SECRET) — deterministic derivation from stable env var.","confirmed_closed":"Yes — public key stable since 30 Jul 2026."},{"date":"2026-07-22","version":"0.6.x","type":"FIX","id":"CHG-002","title":"F-1: DENY only reachable via irreversible=true signal","found_by":"Alkama Eqbal, CLARA Run 1 (2026-07-22)","description":"DENY was only triggered by irreversible flag, not by consequence tier alone. Autonomous CRITICAL/EMERGENCY agents without human present would receive ESCALATE (no human to escalate to) rather than DENY.","fix":"Autonomous DENY upgrade: CRITICAL/EMERGENCY without human present upgrades ESCALATE to DENY.","confirmed_closed":"Yes — Run 2 showed 9 DENYs on dangerous actions."}],"open_items":["CV-005 anomaly: UNMODIFIED state case returned STATE_CHANGED — harness or engine? Recheck pending.","Multi-party attestation not wired into live actuator execute path","Execution continuity and consequence verification standalone — not yet in live intercept path","Independent impl-to-spec audit: TLA+ mapping not yet reviewed by independent party","HSM/KMS: signing key not yet hardware-backed","External co-signer: VeriSigil currently holds both keys"],"how_to_report":"raheem@verisigilai.com — confirmed findings published here with attribution by mutual written approval","timestamp":"2026-11-06T22:31:46.521217+00:00"}