Repository navigation
[ticket-020] feat(tui): add PyteTerminalSurface 2D terminal surface driver and dynamic PTY TerminalSession - #20
Conversation
… and raw/resize PTY session driver
… PyteTerminalSurface
There was a problem hiding this comment.
Validator approval after policy checks for exact head 556f8d9e781e61efe64711d3ad38d65a80b6873f.
Ticket: ticket-020
Correlation ID: local-semcod-testwins-pr-20-ticket-020
Model: openai/cursor-auto
Reviewed diff chunks: 3
Advisory LLM verdict: REQUEST_CHANGES
Advisory summary: Reviewed all 3 diff chunk(s). The visible chunk safely introduces bounded terminal-surface construction, ANSI/truecolor normalization, cell inspection, resizing, output-budget enforcement, and focused tests for rendering, parity detection, raw input, and PTY resizing. No unresolved code or security defects are evident in this chunk. | The PTY session implementation is generally careful, and all required unit/browser checks passed. However, the visible box-detection logic appears to reject ordinary Unicode box frames, undermining the primary feature. | The visible terminal backend changes correctly add validated dimensions, color configuration, raw input, and resize actions while preserving bounded inputs, direct process spawning without an implicit shell, output limits, and exit-code handling. Task-level validation consistently restricts the new options to the terminal backend.
Advisory findings: In detect_boxes, the bottom-edge condition requires that no character between the bottom corners belongs to ALL_CORNERS_AND_WALLS. A normal box such as └──┘ contains horizontal wall characters in exactly that slice, so—consistent with the set's name—it will not be detected. Consequently, valid boxes may be reported as TW-TUI-BOX-BROKEN. Validate the expected bottom horizontal border instead of rejecting wall characters (and likewise validate the top edge).
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: 030b23d0ed0247c83c2590a45f457053254efbf1...556f8d9e781e61efe64711d3ad38d65a80b6873f
Change digest: 8a22463a9ddfce75eb1db45879ee8f6189c39f8798dd79a498b50f4683fc5a53
Score: 48/100 (M), estimated 59 min, split recommended: true
Affected services/components: repository-wide/unclassified
Machine-readable radar JSONL and SVG
{"actual_change":{"additions":668,"base_sha":"030b23d0ed0247c83c2590a45f457053254efbf1","binary_files":0,"categories":{"code":2,"configuration":1,"docs":1,"tests":1},"change_digest":"8a22463a9ddfce75eb1db45879ee8f6189c39f8798dd79a498b50f4683fc5a53","comparison":"030b23d0ed0247c83c2590a45f457053254efbf1...556f8d9e781e61efe64711d3ad38d65a80b6873f","deletions":39,"file_count":5,"files":["project/ticket-020/README.md","project/ticket-020/intent.json","tests/test_terminal_surface.py","testwins/integrations/terminal.py","testwins/tasks.py"],"head_sha":"556f8d9e781e61efe64711d3ad38d65a80b6873f","service_count":0,"services":[]},"assessment_mode":"observed-pr","axes":{"coupling":3,"delivery":2,"scope":3,"uncertainty":3,"validation":1},"complexity":"M","confidence":0.9,"diagnostics":["RADAR-ACCEPTANCE-MISSING","RADAR-BUDGET-EXCEEDED"],"estimate":{"budget_minutes":30,"minutes":59,"within_budget":false},"impact":{"components":["project","tests","testwins"],"files":["project/ticket-020/README.md","project/ticket-020/intent.json","tests/test_terminal_surface.py","testwins/integrations/terminal.py","testwins/tasks.py"],"public_interfaces":[],"runtime_dependencies":0},"schema":"subactor.ticket-radar/v1","score":48,"split":{"parts":[{"estimated_minutes":17,"name":"Implement project","scope":["project"]},{"estimated_minutes":17,"name":"Implement tests","scope":["tests"]},{"estimated_minutes":17,"name":"Implement testwins","scope":["testwins"]},{"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-020"}<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128" role="img"><title>ticket-020: [ticket-020] feat(tui): add PyteTerminalSurface 2D terminal surface driver and dynamic PTY TerminalSession</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 89,56 79,85 59,71 48,59" 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">M · 59m</text></svg>DECISION D-020-5035
TICKET ticket-020
HEAD_SHA 556f8d9e781e61efe64711d3ad38d65a80b6873f
CORRELATION_ID local-semcod-testwins-pr-20-ticket-020
ACTOR agent:ifuri-validator-agent[bot]
APPLIED_RULE P-CORE-015
INPUT author_login = "tom-sapletta-com"
INPUT observed_checks = ["docker=SKIPPING","browser=PASS","browser=PASS","unit=PASS","unit=PASS"]
INPUT required_checks = ["unit","browser"]
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/testwins","pull_request":20,"head_sha":"556f8d9e781e61efe64711d3ad38d65a80b6873f","base_sha":"385095426e3bc2b2dd38bfbebdfe8e7daef589a2","diff_sha256":"005c736f1cbd41760bead2bc2856d47886c5e8ddac1706e80613493968beb47c"},"policy":{"policy_schema":"subactor.validator/semantic-review-policy/v1","policy_version":1,"policy_sha256":"676cb4516bbfed2a000e40b9b1b6e4a430ecc761ec546aeb53d721a1905cfdd7","required":false,"critical_paths":[],"observed_paths":["project/ticket-020/README.md","project/ticket-020/intent.json","tests/test_terminal_surface.py","testwins/integrations/terminal.py","testwins/tasks.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":"030b23d0ed0247c83c2590a45f457053254efbf1","head_sha":"556f8d9e781e61efe64711d3ad38d65a80b6873f","change_digest":"8a22463a9ddfce75eb1db45879ee8f6189c39f8798dd79a498b50f4683fc5a53","score":48,"complexity":"M","estimated_minutes":59,"split_recommended":true,"services":[],"authority":"ADVISORY","promotion":"FORBIDDEN"}
VERDICT APPROVE AUTHORITY DETERMINISTIC
REJECTED REQUEST_CHANGES BECAUSE NO_UNSAFE_CHANGE_REASON_FOUND
ADVISORY llm_verdict = "REQUEST_CHANGES" MODEL "openai/cursor-auto"
ASSERT VERDICT_AUTHORITY != "ADVISORY"There was a problem hiding this comment.
Validator approval after policy checks for exact head 556f8d9e781e61efe64711d3ad38d65a80b6873f.
Ticket: ticket-020
Correlation ID: local-semcod-testwins-pr-20-ticket-020
Model: zai/glm-5.3
Reviewed diff chunks: 3
Advisory LLM verdict: APPROVE
Advisory summary: Reviewed all 3 diff chunk(s). Chunk 1 of the ticket-020 diff adds the Pyte 2D surface inspector scaffolding, PyteTerminalSurface (dimension bounds, pyte screen/stream, cell access, color normalization), box-drawing glyph tables, and comprehensive tests covering truecolor decoding, parity detectors, modal occlusion, raw PTY keys, live resize, and backward-compatible execute(). No security issues observed; env handling claims no host secret leakage and no subprocess env is passed wholesale in the visible code. Required checks (unit, browser) passed. | Chunk adds a Pyte-based terminal surface with box detection, TUI parity audit, and a POSIX PTY session helper. Logic is coherent: occlusion handling for modal overlays, hex token drift checks, winsize/SIGWINCH resize, and graceful process teardown with SIGTERM/SIGKILL escalation. Env allowlist avoids leaking secrets to child processes. | Terminal backend extension adds cols/rows/color options, send_raw and resize actions with proper validation in both the integration and task schema. Regex patterns are compiled before spawning, cwd is confined, no shell invocation, and output budgeting retained. Required checks (unit, browser) all pass.
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: 030b23d0ed0247c83c2590a45f457053254efbf1...556f8d9e781e61efe64711d3ad38d65a80b6873f
Change digest: 8a22463a9ddfce75eb1db45879ee8f6189c39f8798dd79a498b50f4683fc5a53
Score: 48/100 (M), estimated 59 min, split recommended: true
Affected services/components: repository-wide/unclassified
Machine-readable radar JSONL and SVG
{"actual_change":{"additions":668,"base_sha":"030b23d0ed0247c83c2590a45f457053254efbf1","binary_files":0,"categories":{"code":2,"configuration":1,"docs":1,"tests":1},"change_digest":"8a22463a9ddfce75eb1db45879ee8f6189c39f8798dd79a498b50f4683fc5a53","comparison":"030b23d0ed0247c83c2590a45f457053254efbf1...556f8d9e781e61efe64711d3ad38d65a80b6873f","deletions":39,"file_count":5,"files":["project/ticket-020/README.md","project/ticket-020/intent.json","tests/test_terminal_surface.py","testwins/integrations/terminal.py","testwins/tasks.py"],"head_sha":"556f8d9e781e61efe64711d3ad38d65a80b6873f","service_count":0,"services":[]},"assessment_mode":"observed-pr","axes":{"coupling":3,"delivery":2,"scope":3,"uncertainty":3,"validation":1},"complexity":"M","confidence":0.9,"diagnostics":["RADAR-ACCEPTANCE-MISSING","RADAR-BUDGET-EXCEEDED"],"estimate":{"budget_minutes":30,"minutes":59,"within_budget":false},"impact":{"components":["project","tests","testwins"],"files":["project/ticket-020/README.md","project/ticket-020/intent.json","tests/test_terminal_surface.py","testwins/integrations/terminal.py","testwins/tasks.py"],"public_interfaces":[],"runtime_dependencies":0},"schema":"subactor.ticket-radar/v1","score":48,"split":{"parts":[{"estimated_minutes":17,"name":"Implement project","scope":["project"]},{"estimated_minutes":17,"name":"Implement tests","scope":["tests"]},{"estimated_minutes":17,"name":"Implement testwins","scope":["testwins"]},{"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-020"}<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128" role="img"><title>ticket-020: [ticket-020] feat(tui): add PyteTerminalSurface 2D terminal surface driver and dynamic PTY TerminalSession</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 89,56 79,85 59,71 48,59" 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">M · 59m</text></svg>DECISION D-020-4620
TICKET ticket-020
HEAD_SHA 556f8d9e781e61efe64711d3ad38d65a80b6873f
CORRELATION_ID local-semcod-testwins-pr-20-ticket-020
ACTOR agent:ifuri-validator-agent[bot]
APPLIED_RULE P-CORE-015
INPUT author_login = "tom-sapletta-com"
INPUT observed_checks = ["docker=SKIPPING","browser=PASS","browser=PASS","unit=PASS","unit=PASS"]
INPUT required_checks = ["unit","browser"]
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/testwins","pull_request":20,"head_sha":"556f8d9e781e61efe64711d3ad38d65a80b6873f","base_sha":"385095426e3bc2b2dd38bfbebdfe8e7daef589a2","diff_sha256":"005c736f1cbd41760bead2bc2856d47886c5e8ddac1706e80613493968beb47c"},"policy":{"policy_schema":"subactor.validator/semantic-review-policy/v1","policy_version":1,"policy_sha256":"676cb4516bbfed2a000e40b9b1b6e4a430ecc761ec546aeb53d721a1905cfdd7","required":false,"critical_paths":[],"observed_paths":["project/ticket-020/README.md","project/ticket-020/intent.json","tests/test_terminal_surface.py","testwins/integrations/terminal.py","testwins/tasks.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":"030b23d0ed0247c83c2590a45f457053254efbf1","head_sha":"556f8d9e781e61efe64711d3ad38d65a80b6873f","change_digest":"8a22463a9ddfce75eb1db45879ee8f6189c39f8798dd79a498b50f4683fc5a53","score":48,"complexity":"M","estimated_minutes":59,"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 "zai/glm-5.3"
ASSERT VERDICT_AUTHORITY != "ADVISORY"
Resolves B10: adds 2D ANSI terminal grid observation (
PyteTerminalSurface), continuous box-border detection with floating modal occlusion support, and dynamicTIOCSWINSZ/SIGWINCHTerminalSession.