End-to-end flow simulation + replay ที่พิสูจน์ว่า audit trail ครบ (#7) - #19
Merged
Conversation
…plete (#7) Milestone v0.1's closing gate: a governed job driven end to end through the real state machine, everything it emits filed in the real audit log, and the trail then read back to check it accounts for what happened. Delivered as both forms issue #7 allows. `simulation/e2e_flow.py` is what a person runs to watch a job move; `simulation/tests/test_e2e_flow.py` is what fails a pull request when a guarantee regresses. Both run in CI. The forward path is read out of `states.py`, not retyped -------------------------------------------------------- `flows.main_line()` derives DRAFT → … → COMPLETED from the transition table by discarding the exits available from nearly everywhere, and raises rather than choosing if the table ever stops naming one way forward. The flow #7 spells out appears exactly once, as the thing that derivation is compared *against* — so a disagreement between the issue and the table fails the check instead of the simulation quietly following the issue and reporting success. `states.reachable_from()` folds AWAITING_APPROVAL's per-job return edge into the table read, so the engine and anything reading the trail back ask the same question of the same source. Replay is a completeness proof, not a convenience ------------------------------------------------- `devfactory_observability.replay` rebuilds a job from its events alone. Every STATE_TRANSITION names the state it left, so a replay holding a running state notices a record that is missing or out of order — which the engine cannot, having written them. It re-checks the guarantees against what was actually written: every edge against `states.reachable_from`, every APPROVED against a GOVERNANCE_DECISION that really produced it, and the direction lock against the record rather than the engine's memory of it. `conformance/payload_check.py` now drives the same flows from `flows.py`. It asks a different question — do the payloads conform — but it should not be asking it about a different journey. Two limits recorded rather than smoothed over --------------------------------------------- A trail truncated at the end is detectable only for a job that completed: JOB_COMPLETED is the one record that says a transition should have followed. Nothing says so for FAILED, CANCELLED, TIMED_OUT, or a job still in flight, and closing that needs a per-job sequence number in event/v1 — a contract change. `UnauditedExecution` cannot fire on a table-consistent trail, since TASK_PLANNING is reachable only from APPROVED and APPROVED is refused without a decision. It is a structural backstop, kept for the reason job.py keeps ExecutionBeforeApproval. Nothing here weakens an existing guarantee, and no transition is declared outside `states.py`. 350 tests → 441; payload conformance unchanged at 13 passed, 0 fail. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
ปิด #7 — ประตูสุดท้ายของ v0.1.0 · job ถูกขับผ่าน state machine จริง สิ่งที่มัน emit ถูกเก็บใน
audit log จริง แล้ว อ่านย้อนกลับเพื่อพิสูจน์ว่า trail อธิบายสิ่งที่เกิดขึ้นได้ครบ
รันยังไง
script คือสิ่งที่ issue ขอและเป็นของที่คนนั่งดูได้ · suite คือของที่กันไม่ให้ guarantee ถอยหลัง
ตอนไม่มีใครดู · CI รันทั้งคู่
ผลตรวจ
pytestทั้งชุดsimulation/e2e_flow.pyconformance/payload_check.pyจุดที่ตั้งใจออกแบบให้ไม่หลอกตัวเอง
flow หลัก derive จากตาราง ไม่ใช่เขียนตามที่ issue บอก —
MAIN_LINEคำนวณจาก_PROGRESSIONแล้ว assert ว่าตรงกับลำดับที่ #7 เขียนไว้ ถ้าตารางกับ issue ขัดกันเมื่อไหร่ check ข้อนี้แดง
แทนที่จะเดินตาม issue แล้วรายงานผ่านทั้งที่ตารางเปลี่ยนไปแล้ว
governance gate ถูกทดสอบจากสองทาง — เข้า POST_APPROVAL โดยไม่มี
Decisionไม่ได้ทั้ง 5 state· และ ยัด
_state=APPROVEDเข้าไปตรง ๆ ก็ยังโดนExecutionBeforeApprovalเพราะ gate ผูกกับrecord ไม่ใช่ flag (ผลของ #5) · อ่านย้อนจาก log ด้วย: ลบ
GOVERNANCE_DECISIONออก → replay ปฏิเสธreplay พิสูจน์ด้วยการทำลาย — ลบ transition ใบไหนก็ได้ใน 7 ใบ · สลับลำดับ · ปลอม edge
IN_PROGRESS→COMPLETEDที่ตารางไม่มี → จับได้ทุกกรณี (UndeclaredTransition)FAILED ครบทั้ง 5 state ที่
FAILABLEอนุญาต และถูกปฏิเสธครบทั้ง 4 state ที่เหลือ· recovery ผ่าน job ใหม่ที่
supersedesต้องผ่าน governance ใหม่ตาม RFC-0007 Decision 1trail ที่ถูกตัดท้ายตรวจไม่ได้ ยกเว้น job ที่จบด้วย
COMPLETEDทุก record ถูกตรวจโดย record ถัดไป (ใบถัดไปบอกว่าออกจาก state ไหน) แต่ ไม่มีอะไรตรวจใบสุดท้าย
—
JOB_COMPLETEDช่วยได้เฉพาะ job ที่จบสวย · ผลคือ trail ที่หาย event ท้ายสุดของ job ที่จบเป็นFAILED/CANCELLED/TIMED_OUTหรือ job ที่ยังเดินอยู่ replay ผ่านเรียบร้อยโดยได้ state ก่อนหน้าใบที่หายปิดจริงต้องมี per-job sequence number ใน
event/v1ซึ่งเป็น wire shape ของagent-platform(RFC-0005 Rule 1) จึงไม่ใช่สิ่งที่ตัดสินใน PR นี้ · สิ่งที่ทำแทน:
IncompleteSettlementปิดเท่าที่ปิดได้โดยไม่แตะสัญญาtest_a_trail_cut_short_at_a_terminal_other_than_completed_still_replaysที่ยืนยันว่ามันตรวจไม่ได้ — บันทึกช่องว่างไว้เป็นโค้ด ไม่ใช่ซ่อน
→ ควรเปิด issue แยกเรื่อง sequence number
ที่ไม่แตะตามขอบเขต
REQUIRE_CHANGES(ยังไม่มีปลายทาง —payload_checkยังยืนยันว่าถูกปฏิเสธ) ·APPROVEDtimeout (#17) · ไม่มี transition ใดถูก hard-code นอกstates.py·ไม่มี guarantee เดิมถูกลดความเข้มลง
Closes #7