feat(compiler): emit identifier_crop — arm identity-on-pixels for remote-display/pixel workflows#158
Merged
Merged
Conversation
…ote-display workflows The pixel-compare identity tier (runtime.identity.verify_pixel_identity) has been wired since the identity-ladder work, but the COMPILER never emitted anchor.identifier_crop, so Citrix/RDP/remote-display bundles replayed with identity-on-pixels unarmed. Close the gap end to end, extending the #120 reference machinery (superseded unmerged by #135): - compile: emit anchor.identifier_crop + identifier_region for identity-armed clicks without structured identity (tight box of the surviving OCR identity band lines, via context_region_from_lines ported from #120), or at an explicitly marked region. Crops land under templates/identifiers/ so they ride the exact seal-template-crops (#113) handling: manifest-hashed, sealed to .enc under TEMPLATE_AAD on encrypted save, decrypted in memory on load, covered by run-gate 5 and the governed-run asset snapshot. No report rail touches them. - explicit marking (mirrors --secret): `record --identifier FIELD` (web, in-page rect per click; wins over the band box and forces a crop even alongside structured identity) and `record --backend windows|macos|linux|rdp --identifier X,Y,W,H` (region stamped additively into meta.json; field-name syntax refused loudly on a pixel capture). - explicit degrade, never silent: new Step.identifier_crop_missing_reason (mirrors identity_unarmed_reason) records WHY a step compiled crop-less (structured-owns-identity / identity-unarmed / no-band-lines / marked-region-invalid). - lint (mirrors effect coverage): per-bundle pixel-identity coverage (identifier_crop_armed_steps / identity_armed_steps) + a missing_identifier_crop finding per armed crop-less step (warn on band-only identity, info under structured identity), carrying the degrade reason. - runtime: thread workflow into Replayer._identifier_crops so a SEALED crop decrypts from the in-memory store and still arms the tier. Safety unchanged: PIXEL_VERIFY_ENABLED stays False — the tier remains MISMATCH-or-ABSTAIN, so a crop can only add a safe HALT on a wrong identifier, never a pixel false-accept (pinned by test). Structured recordings still write no identity pixels at rest unless marked. Tests: compiler emission/marking/degrade/sealing (10), lint coverage (7), web-recorder marking e2e, desktop CLI parse + meta stamp; wrong-MRN drives a pixel-tier MISMATCH through the real Replayer ladder on plaintext AND sealed bundles. Claims: identifier-crop-compile-emission (supported, fixture-scoped caveats); VERIFICATION.md regenerated; RECORDING.md documents --identifier. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
abrichr
force-pushed
the
feat/compiler-identifier-crop
branch
from
July 19, 2026 09:46
485c142 to
e234f79
Compare
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.
What
The runtime's pixel-compare identity tier (
runtime.identity.verify_pixel_identity, the "right record on a no-DOM surface" check) has been fully wired since the identity-ladder work — but the COMPILER never emittedanchor.identifier_crop, so every Citrix/RDP/remote-display bundle ran with identity-on-pixels unarmed (flagged July 14, re-verified in the July 19 multisubstrate design review). This PR closes that gap end to end:Compiler emission (extends the #120 machinery, superseded-not-merged via #135)
context_region_from_lines+ the shared_kept_context_linesband filter from thefeat/macos-backend-pixel-pathreference branch (feat: macOS pixel backend selector + compile-time identifier crop (arm pixel identity tier) #120) intoruntime/identity.py— same filter ascontext_from_lines, single definition.compiler.compilenow emitsanchor.identifier_crop+identifier_regionfor every identity-armed click that captured no structured identity (the pixel-recording case), cropping the tight bounding box of the surviving OCR identity-band lines.templates/identifiers/<step>.png— deliberately undertemplates/so they ride the exactseal-template-crops(feat: seal template screenshot crops in the AEAD bundle (close at-rest image-PHI gap) #113) lineage: hashed into the integrity manifest, sealed to.encunderTEMPLATE_AADonsave(encrypt=True)with plaintext removed, decrypted in memory on load, and covered by run-gate 5's cleartext-asset check. No new PHI surface, no report rail touches them.Record-time marking (mirrors the
--secretfield-marking pattern)record --identifier FIELD(web): the in-page listener captures the marked field's rect at each click (identifier_regionon the event). An explicit marking wins over the automatic band box and forces a crop even alongside structured identity (for structural recordings later replayed over Citrix/RDP).record --backend windows|macos|linux|rdp --identifier X,Y,W,H: a pixel capture has no field identity, so the region is marked once per recording; stamped additively intometa.jsonpost-convert (converter contract unchanged). Field-name syntax on a desktop backend is refused loudly (mirrors the--secretrefusal).Explicit degrade, never silent
New
Step.identifier_crop_missing_reason(mirrorsidentity_unarmed_reason) records WHY an identity-applicable step compiled crop-less. Taxonomy:IDCROP_REASON_STRUCTURED— structured identity owns the step; no identifier pixels at rest (mark with--identifierto force).IDCROP_REASON_UNARMED— identity not armed at all (seeidentity_unarmed_reason).IDCROP_REASON_NO_BAND_REGION— band kept no lines to bound a crop from.IDCROP_REASON_MARKED_INVALID— marked region degenerate/outside the frame (prefixed onto whichever fallback reason applies; a valid band still yields a crop, with a compile-time warning).Lint / certification coverage (mirrors the effect-coverage pattern)
lint_workflownow reportsidentifier_crop_armed_steps / identity_armed_steps("pixel identity coverage: N/M …") and emitsmissing_identifier_cropper armed step without a crop — warn when identity rests only on the OCR band (the under-armed Citrix case), info when structured identity covers the step; the finding carries the compiler's degrade reason.Runtime fix
Replayer._identifier_cropsnow threadsworkflowinto_asset_bytes, so a SEALED crop in an encrypted bundle decrypts from the in-memory store and still arms the tier (previously the sealed path would silently abstain).Safety posture (unchanged guarantees)
PIXEL_VERIFY_ENABLEDstays False: the pixel tier remains MISMATCH-or-ABSTAIN. Emitting a crop can only add a safe HALT on a wrong identifier — it can never authorize a match, so zero-false-accept is preserved (pinned by test).Tests (all new paths covered on synthetic fixtures)
tests/test_compile_identifier_crop.py(10): crop emitted + region correct + manifest-hashed on a pixel recording; structured recording writes no crop and records why; event/meta markings win; invalid marking degrades to band with warning; malformed marking fails loud; unarmed reason; encrypted save seals the crop (no cleartext,.encpresent, decrypts on load); wrong-MRN drives a pixel-tier MISMATCH through the realReplayer._verify_identityladder on both plaintext and sealed bundles; same-value never pixel-VERIFIES.tests/test_identifier_crop_lint.py(7): coverage counts/fraction, warn-vs-info severity, degrade reason in the finding, render lines.tests/test_interactive_recorder.py:--identifier FIELDrecords the rect in-page and the compiled bundle carries the crop at that region.tests/test_desktop_record.py: CLI region parse + refusal, meta.json stamp.Claims: new
identifier-crop-compile-emissionentry (tiersupported, honest caveats: fixture-proven mechanism, no substrate re-qualification, tier stays veto-only).docs/VERIFICATION.mdregenerated. Docs:docs/desktop/RECORDING.mdgains the--identifiersection.Full non-E2E suite + ruff (check/format) + mypy (base + strict-safety scope) green locally.
Local notes: the only 2 local failures (
tests/test_pixel_identity_probe.pyskimage import) are a pre-existing local-environment issue —skimageis absent from the project venv and resolves to a binary-incompatible anaconda install; those files are untouched by this PR.🤖 Generated with Claude Code