Implement the audit event log and payload conformance - #15
Merged
Conversation
Closes issue #6 and, with it, ADR-0006 requirement 2 — a conformance test in CI that validates real payloads. conformance.status moves off unknown for the first time. The event vocabulary is now all seven canonical types in one place, with a note on which plane emits which; the state machine still emits only its own three. Event grew the surface RFC-0008 needs for inbound events: job_id optional, an event_type that can hold a string outside our vocabulary, correlation_id, and a source that an external event keeps. packages/observability holds storage and intake. Two design points are the substance rather than detail. Tenant isolation is a partition per tenant, not one list with a filter, because RFC-0006 states isolation as a storage-layer guarantee and says a WHERE clause does not satisfy it - a filter puts one forgotten predicate between two tenants, and there is no predicate to forget when there is no shared list. Append-only is the absence of update, delete, and clear rather than a flag, and digest() turns the claim into something checkable: a shortened or altered history does not reproduce. Intake refuses rather than repairs. A placeholder job_id is rejected instead of being stored or quietly turned into absence, because the sender's intent is ambiguous and an immutable log is the wrong place to resolve an ambiguity by guessing. An unresolvable tenant is rejected outright - a lost event is a visible gap, while one tenant's activity in another tenant's trail is not. An unparseable timestamp is refused rather than replaced with ours, which would misreport when the thing happened. An unrecognised event_type is none of those things: event/v1 says keep it and skip interpreting it, so it is kept. conformance/payload_check.py runs six jobs across two tenants through the real engine - every terminal state, the mid-run pause, rejection and resubmission, recovery by supersession - plus inbound external events, then validates all 37 emitted payloads. Nothing is hand-written to please the schema. It also asserts the eight event/v1 guarantees JSON Schema cannot express. The approach follows care-agent-platform's payload_check.py, which got here first. The first run earned its keep by finding a contract defect rather than one of ours: event/v1 $defs.EventType is still a closed enum, which contradicts the same file's platform_rules ("keep an unknown event_type, never drop or fail") and the RFC-0009 amendment to ADR-0006 Rule 2 that made the vocabulary open this morning. Filed as agent-platform#17. Recorded as a known gap scoped to two conditions at once - the error must be at event_type and the event must be external - with an expiry date, since ADR-0006 forbids a permanent exception. Any other failure turns the run red. The manifest now reads passing and conforming, with the gap listed the way care-agent-platform lists its own. One honest caveat is recorded there and in the workflow: these checks only block a merge once branch protection marks them required, which is a repository setting and not something a file here can assert. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Aug 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #6 — และปิด ADR-0006 ข้อ 2 ด้วย ·
conformance.statusขยับออกจากunknownเป็นครั้งแรก🔍 รอบแรกที่รัน จับ contract defect ได้ — ไม่ใช่ของเรา
event/v1$defs.EventTypeยังเป็น enum ปิด 7 ค่า ซึ่งขัดกับ 3 อย่างพร้อมกัน:platform_rulesในไฟล์เดียวกัน — "consumer ที่เจอevent_typeที่ไม่รู้จักต้องเก็บ event ไว้ ห้าม drop ห้าม fail" · กฎที่อธิบายวิธีรับมือค่าที่ schema ไม่ยอมให้มีอยู่descriptionของ field เอง ที่เขียนว่า 🔓 ชุดเปิดแจ้งเป็น agent-platform#17 พร้อมเสนอรูปแบบแก้ (
EventTypeNameที่บังคับ pattern แต่ไม่ปิดชุดค่า)นี่คือเหตุผลทั้งหมดที่ ADR-0006 ยืนกรานว่า payload จริง ไม่ใช่
$refcheck —$refเราถูกทุกจุด pin ถูกทุกตัว แต่ payload ที่ contract บอกเองว่าต้องรับได้ ยัง validate ไม่ผ่านScope ของ #6
job_idoptional · subject required ·tenant_idrequiredOut of scope ตามที่ issue ระบุ: metrics backend · dashboard ·
correlation IDs← RFC-0008 เพิ่มเข้ามาแล้ว จึงทำด้วยpackages/observability— 2 จุดที่เป็นสาระtenant isolation เป็น partition ไม่ใช่ filter
RFC-0006 ระบุว่า isolation ต้องอยู่ที่ ชั้นเก็บ และบอกตรง ๆ ว่า
WHERE tenant_id = ?ไม่นับlist เดียวที่กันด้วย filter คือการเอา predicate หนึ่งตัวไปวางระหว่าง tenant สองราย · ที่นี่ไม่มี predicate ให้ลืม เพราะไม่มี list ที่แชร์กัน
ทุกการอ่านต้องระบุ
tenant_id· ไม่มี method ไหนคืน event ข้าม tenant —tenants()และการ iterate คืนแค่ id ·len()เป็นตัวเลขรวมที่ไม่พา content ของ tenant ไหนออกมา · tenant ที่ไม่รู้จักอ่านได้เป็นว่าง ไม่ raise เพื่อไม่ให้การลองยิงบอกอะไรกับคนถามappend-only คือการไม่มี method นั้น
ไม่มี
updatedeletecleartruncate— API ที่ไม่มีทางแก้ประวัติ ถูกเกลี้ยกล่อมให้แก้ประวัติไม่ได้ ซึ่งแข็งกว่า flag ที่ใครก็ส่งได้digest(tenant_id)เป็น hash chain บน event id ตามลำดับที่เขียน — ทำให้คำว่า append-only ตรวจได้ ไม่ใช่แค่อ้าง · เอา digest ไว้ ทำงานต่อ แล้วเอาอีกครั้ง: การโตทำให้เปลี่ยน และการแก้/ลบ record เก่าก็ทำให้เปลี่ยนเหมือนกันextend()ไม่ atomic โดยเจตนา — append บางส่วนเก็บตัวที่ถูกต้องไว้แล้วรายงานตัวที่ไม่ถูก · การทิ้ง record ที่รับไปแล้วเพื่อลงโทษตัวที่มาทีหลังคือการทิ้งประวัติที่เกิดขึ้นจริงIntake — ปฏิเสธ ไม่ซ่อมให้
job_idjob_id="none""-""0"…FabricatedIdentifierMissingTenant— reject ที่ intake ไม่ default ให้NoneMissingTenant— resolver ที่ตอบไม่ได้ ไม่ถูกเดาแทนMissingSubjectsource.systemExternalSourceRequiredoccurred_atparse ไม่ได้ValueError— ใส่เวลาของเราแทนคือการรายงานเวลาผิดใน record ที่แก้ไม่ได้event_typeที่ไม่รู้จักis_recognisedเป็นFalsesource.kindถูกบังคับเป็นexternalไม่ใช่เชื่อค่าที่ส่งมา — event ที่เข้ามาทางนี้เป็น external ด้วยข้อเท็จจริงที่มันมาถึงที่นี่ ไม่ว่ามันจะอ้างตัวว่าอะไรการเดา tenant ถือว่าแย่กว่าการเสีย event — event ที่หายเป็นช่องว่างที่มองเห็น ส่วนกิจกรรมของ tenant หนึ่งที่ไปอยู่ใน trail ที่แก้ไม่ได้ของอีก tenant ไม่มีใครเห็น
conformance/payload_check.pyรัน 6 job ข้าม 2 tenant ผ่าน engine จริง — ครบทุก terminal state · pause กลางคันแล้ว resume · reject แล้วยื่นใหม่ · recovery ด้วย
supersede()— บวก event จากภายนอกที่ไม่มี job เป็นต้นเหตุ · แล้ว validate payload ทั้ง 37 ตัว ที่ระบบผลิตออกมาไม่มี fixture ที่เขียนขึ้นเพื่อให้ schema ผ่านแม้ตัวเดียว · ถ้า payload ไม่ conform ทางแก้คือ code หรือ issue ที่ upstream ไม่ใช่แก้ fixture
และตรวจ guarantee 8 ข้อที่ JSON Schema ตรวจไม่ได้:
โครงตาม
payload_check.pyของcare-agent-platformที่ทำก่อนและควรลอกมากกว่าคิดใหม่known_gaps— แคบที่สุดเท่าที่จะแคบได้การยกเว้นต้องเข้าเงื่อนไข 2 ข้อพร้อมกัน — error ต้องอยู่ที่
event_typeและ event ต้องมีsource.kind: external· failure อื่นทุกแบบทำให้ run แดงมีวันหมดอายุ 2026-11-18 และ
payload_checkตรวจอายุเองเป็น check ข้อ 3 — ADR-0006 ห้ามยกเว้นถาวรmanifest
ครบ 3 ข้อของ ADR-0006 — manifest · conformance test ที่ validate payload จริงใน CI · release gate (job
core+conformanceทุก PR) · บันทึกgapsแบบเดียวกับที่care-agent-platformทำcheck พวกนี้จะบล็อกการ merge ได้จริงต่อเมื่อเปิด branch protection แล้วตั้งเป็น required — เป็น repo setting ไม่ใช่สิ่งที่ไฟล์ใน PR นี้ยืนยันได้ · เขียนกำกับไว้ทั้งใน manifest และหัว workflow แล้ว เหมือนที่ทำกับ
CODEOWNERS(เรื่องเดียวกัน ยังไม่ได้เปิดทั้งคู่)Impacted planes
Observability เป็นหลัก · Control แตะเฉพาะ
EventTypeครบ 7 และEventที่กว้างขึ้นสำหรับ event ภายนอก — job state machine ไม่เปลี่ยนพฤติกรรมสักจุด (243 tests เดิมผ่านหมด)Risk analysis
known_gapsกลายเป็นข้ออ้างทั่วไป (high) → ต้องเข้า 2 เงื่อนไขพร้อมกัน · มีวันหมดอายุที่ตรวจอัตโนมัติ · การขยายรายการต้องมี issue ใหม่passingทั้งที่ยังมี gap (medium) → ตามแบบที่care-agent-platformทำและ platform รับแล้ว (gaps RFC needed: which states may reach FAILED #14 Implement the audit event log and payload conformance #15 กับ statuspassing) · gap อยู่ฝั่ง contract ไม่ใช่ implementation และ 35 จาก 37 payload ที่ เราผลิตเอง ผ่านหมดextend()ไม่ atomic (low) → เจตนา พร้อมเทสต์ที่ยืนยันพฤติกรรมTASK_ASSIGNEDEXECUTION_STARTEDEXECUTION_FAILEDยังไม่มีใครส่ง เพราะ orchestration/execution เป็น Phase 1: End-to-end flow simulation #7Related
#6 · #2 (state machine ที่ผลิต payload) · #5 #7 ที่เหลือ · agent-platform#17
🤖 Generated with Claude Code