Skip to content

perf(store): compute the global evidence revision with one scandir pass (ticket-066) - #67

Merged
ifuri-validator-agent[bot] merged 1 commit into
mainfrom
ticket/066-evidence-revision-scandir
Sep 11, 2026
Merged

perf(store): compute the global evidence revision with one scandir pass (ticket-066)#67
ifuri-validator-agent[bot] merged 1 commit into
mainfrom
ticket/066-evidence-revision-scandir

Conversation

@tom-sapletta-com

Copy link
Copy Markdown
Contributor

Why

PlanfileStore._evidence_revision() is part of every ticket list response signature (api/server.py::_ticket_snapshot_signature) and of the SQLite index freshness signature. On the local Subactor workspace there are 4,454 per-ticket evidence files; Path.glob("*.jsonl") + Path.stat() cost ~125 ms per call, paid on every /tickets request (≈50/min from Control and host agents).

Change

One os.scandir pass with DirEntry.stat(), sorted by name. Same tuple, same ordering, same invalidation semantics.

Measured inside the running planfile 0.1.124 container (10-call average, identical result): 125 ms → 32 ms.

Tests

  • New test_evidence_revision_matches_glob_and_stat_listing: equality with the previous sorted(glob) + stat listing, including a hidden file, a directory named *.jsonl, a dangling symlink, a non-matching extension and a missing directory; an append changes the revision.
  • Full suite: 487 passed, 6 skipped.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HxJsrPbk3jknTjpr27gyJf

…ss (ticket-066)

Every ticket list response signature and every SQLite index freshness
check stats all per-ticket evidence files. With 4,454 files Path.glob plus
Path.stat took ~125 ms per call; one os.scandir pass returns the identical
tuple in ~32 ms. A regression test pins equality with the previous listing
for hidden files, directories, dangling symlinks and a missing directory.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HxJsrPbk3jknTjpr27gyJf

@ifuri-validator-agent ifuri-validator-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validator approval after policy checks for exact head eaac89786e37116a70a53b979fe628a21b441761.

Ticket: ticket-066
Correlation ID: local-semcod-planfile-pr-67-ticket-066
Model: openrouter/z-ai/glm-5.3-flash
Reviewed diff chunks: 1
Advisory LLM verdict: APPROVE
Advisory summary: Reviewed all 1 diff chunk(s). Refactors PlanfileStore._evidence_revision() from Path.glob + per-path stat to a single os.scandir pass with entry stat, then sorts — preserving tuple content, ordering, and error handling. Semantics match the old behavior: both glob and scandir include directories and symlinks whose names end in .jsonl, hidden files are included by both, per-entry OSError continues are preserved, and a directory-open OSError still returns (). New regression test directly validates equality against the old glob+stat listing across edge cases (hidden file, directory named *.jsonl, dangling symlink, non-matching extension, missing directory) plus revision invalidation on append. Ticket metadata restricts changes to the allowed paths, and no forbidden paths are touched.
Advisory findings: none
The LLM output above is advisory and was not used as the approval trust root.
Semantic review prerequisite: not_required; policy 676cb4516bbfed2a000e40b9b1b6e4a430ecc761ec546aeb53d721a1905cfdd7.

Actual PR impact radar

Exact range: 55e86324ff666984cca92e421162fe65c046573a...eaac89786e37116a70a53b979fe628a21b441761
Change digest: 03c4ad20a61099787bbe5106939d4ef4c45852f780c847211b736708f8386958
Score: 64/100 (L), estimated 78 min, split recommended: true
Affected services/components: repository-wide/unclassified

Machine-readable radar JSONL and SVG
{"actual_change":{"additions":85,"base_sha":"55e86324ff666984cca92e421162fe65c046573a","binary_files":0,"categories":{"code":1,"configuration":1,"docs":1,"tests":1},"change_digest":"03c4ad20a61099787bbe5106939d4ef4c45852f780c847211b736708f8386958","comparison":"55e86324ff666984cca92e421162fe65c046573a...eaac89786e37116a70a53b979fe628a21b441761","deletions":8,"file_count":4,"files":["planfile/core/store.py","project/ticket-066/README.md","project/ticket-066/intent.json","tests/test_sqlite_ticket_index.py"],"head_sha":"eaac89786e37116a70a53b979fe628a21b441761","service_count":0,"services":[]},"assessment_mode":"observed-pr","axes":{"coupling":5,"delivery":3,"scope":3,"uncertainty":3,"validation":2},"complexity":"L","confidence":0.9,"diagnostics":["RADAR-ACCEPTANCE-MISSING","RADAR-BUDGET-EXCEEDED"],"estimate":{"budget_minutes":30,"minutes":78,"within_budget":false},"impact":{"components":["50","api","claude.ai","claude.com","planfile","project","tests"],"files":["50/min","api/server.py","claude.ai/code/session_01HxJsrPbk3jknTjpr27gyJf","claude.com/claude-code","planfile/core/store.py","project/ticket-066/README.md","project/ticket-066/intent.json","tests/test_sqlite_ticket_index.py"],"public_interfaces":["api/server.py"],"runtime_dependencies":0},"schema":"subactor.ticket-radar/v1","score":64,"split":{"parts":[{"estimated_minutes":20,"name":"Define contract and acceptance boundary","scope":["api/server.py"]},{"estimated_minutes":10,"name":"Implement 50","scope":["50"]},{"estimated_minutes":10,"name":"Implement api","scope":["api"]},{"estimated_minutes":10,"name":"Implement claude.ai","scope":["claude.ai"]},{"estimated_minutes":10,"name":"Implement claude.com","scope":["claude.com"]},{"estimated_minutes":10,"name":"Implement planfile","scope":["planfile"]},{"estimated_minutes":15,"name":"Validate and project to trackers","scope":["tests","planfile","github/gitlab/jira projections"]}],"reason":"estimated_minutes_exceed_budget","recommended":true},"standards":[{"id":"wellmanifest/dsl","revision":"6c60fc4e0dd1f1bb74f46a7745e28019908d1203","version":"0.1.0-dev"},{"id":"wellmanifest/ticket-lifecycle","revision":"5bf581907a87b46a13a73e6c033d3abe4d9a306f","version":"0.1.0-dev"},{"id":"wellmanifest/git-lifecycle","revision":"7d77d4b7af57e69bc75c3a0290b3a4805c5c4438","version":"0.2.0-dev"},{"id":"wellmanifest/logs","revision":"48c284ef7a069055c0bcb6b900147ce5e65f8b43","version":"0.3.0"}],"ticket_ref":"ticket-066"}
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128" role="img"><title>ticket-066: perf(store): compute the global evidence revision with one scandir pass (ticket-066)</title><rect width="128" height="128" rx="12" fill="#f8fafc"/><g stroke-width="1"><polygon points="64,55 72,61 69,71 59,71 56,61" fill="none" stroke="#d7dde5"/><polygon points="64,47 80,59 74,78 54,78 48,59" fill="none" stroke="#d7dde5"/><polygon points="64,38 89,56 79,85 49,85 39,56" fill="none" stroke="#d7dde5"/><polygon points="64,30 97,53 84,92 44,92 31,53" fill="none" stroke="#d7dde5"/><polygon points="64,21 105,51 89,99 39,99 23,51" fill="none" stroke="#d7dde5"/><line x1="64" y1="64" x2="64" y2="21" stroke="#aab4c0"/><line x1="64" y1="64" x2="105" y2="51" stroke="#aab4c0"/><line x1="64" y1="64" x2="89" y2="99" stroke="#aab4c0"/><line x1="64" y1="64" x2="39" y2="99" stroke="#aab4c0"/><line x1="64" y1="64" x2="23" y2="51" stroke="#aab4c0"/></g><polygon points="64,38 105,51 79,85 54,78 39,56" fill="#fb923c" fill-opacity="0.45" stroke="#c2410c" stroke-width="2"/><circle cx="64" cy="64" r="3" fill="#c2410c"/><g font-family="sans-serif" font-size="7" fill="#334155"><text x="64" y="11" text-anchor="middle">SCO</text><text x="114" y="48" text-anchor="middle">COU</text><text x="95" y="107" text-anchor="middle">UNC</text><text x="33" y="107" text-anchor="middle">VAL</text><text x="14" y="48" text-anchor="middle">DEL</text></g><text x="64" y="124" text-anchor="middle" font-family="sans-serif" font-size="8" fill="#0f172a">L · 78m</text></svg>
Merge will be attempted after this approval when explicitly authorized. ## Decision record (recomputable)
DECISION D-066-0690
TICKET ticket-066
HEAD_SHA eaac89786e37116a70a53b979fe628a21b441761
CORRELATION_ID local-semcod-planfile-pr-67-ticket-066
ACTOR agent:ifuri-validator-agent[bot]
APPLIED_RULE P-CORE-015
INPUT author_login = "tom-sapletta-com"
INPUT observed_checks = ["notify=PASS","test (3.13)=PASS","ci-loop=PASS","test (3.10)=PASS"]
INPUT required_checks = ["ci-loop","notify"]
INPUT required_checks_source = "protected registry (env/request)"
INPUT reviewer_login = "ifuri-validator-agent[bot]"
INPUT semantic_review_assessment = {"schema":"subactor.validator/semantic-review-assessment/v1","subject":{"repository":"semcod/planfile","pull_request":67,"head_sha":"eaac89786e37116a70a53b979fe628a21b441761","base_sha":"55e86324ff666984cca92e421162fe65c046573a","diff_sha256":"c66ded1617ba0ae2ca3fe50adff41d8bd54fedc873eb432d0f245a6386bdf9f0"},"policy":{"policy_schema":"subactor.validator/semantic-review-policy/v1","policy_version":1,"policy_sha256":"676cb4516bbfed2a000e40b9b1b6e4a430ecc761ec546aeb53d721a1905cfdd7","required":false,"critical_paths":[],"observed_paths":["planfile/core/store.py","project/ticket-066/README.md","project/ticket-066/intent.json","tests/test_sqlite_ticket_index.py"]},"grounding":"full-diff-not-per-finding-proof","execution_authority":false,"status":"not_required","reason":null,"review_sha256":null,"unresolved":[]}
INPUT superseded_checks = []
INPUT ticket_radar_receipt = {"schema":"subactor.ticket-radar/v1","base_sha":"55e86324ff666984cca92e421162fe65c046573a","head_sha":"eaac89786e37116a70a53b979fe628a21b441761","change_digest":"03c4ad20a61099787bbe5106939d4ef4c45852f780c847211b736708f8386958","score":64,"complexity":"L","estimated_minutes":78,"split_recommended":true,"services":[],"authority":"ADVISORY","promotion":"FORBIDDEN"}
VERDICT APPROVE AUTHORITY DETERMINISTIC
REJECTED REQUEST_CHANGES BECAUSE NO_UNSAFE_CHANGE_REASON_FOUND
ADVISORY llm_verdict = "APPROVE" MODEL "openrouter/z-ai/glm-5.3-flash"
ASSERT VERDICT_AUTHORITY != "ADVISORY"

@ifuri-validator-agent
ifuri-validator-agent Bot merged commit 865a57e into main Sep 11, 2026
4 checks passed
@ifuri-validator-agent
ifuri-validator-agent Bot deleted the ticket/066-evidence-revision-scandir branch September 11, 2026 20:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant