Compare commits
2
Commits
946b064470
...
d27fda6be3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d27fda6be3 | ||
|
|
acf7e11114 |
@@ -21,7 +21,7 @@ from ..pdd.product_url import ProductUrl, ProductUrlError, parse_product_url
|
||||
from ..pdd.sku_panel_state import HUMAN_DECLARED_STATES
|
||||
|
||||
|
||||
SANITIZER_VERSION = "t103-privacy-v2"
|
||||
SANITIZER_VERSION = "t103-privacy-v3"
|
||||
EXPECTED_GOODS_ID = "937122477375"
|
||||
EXPECTED_PDD_VERSION = "8.17.0"
|
||||
EXPECTED_DEVICE_MODEL = "PKG110"
|
||||
@@ -29,7 +29,7 @@ EXPECTED_ANDROID_VERSION = "16"
|
||||
EXPECTED_SCREENSHOT_WIDTH = 1080
|
||||
EXPECTED_SCREENSHOT_HEIGHT = 2376
|
||||
EXPECTED_XML_WIDTH = 1080
|
||||
EXPECTED_XML_HEIGHT = 2400
|
||||
EXPECTED_XML_HEIGHT = 2376
|
||||
_ARTIFACT_FILES = ("screenshot.png", "hierarchy.xml")
|
||||
_SHA256_RE = re.compile(r"[0-9a-f]{64}\Z")
|
||||
_BOUNDS_RE = re.compile(r"\[(-?\d+),(-?\d+)\]\[(-?\d+),(-?\d+)\]\Z")
|
||||
|
||||
@@ -48,7 +48,7 @@ def _default_xml() -> str:
|
||||
return (
|
||||
"<hierarchy rotation='0'>"
|
||||
f"<node bounds='[0,0][1080,540]' text='{TEST_ADDRESS}' content-desc='{MASKED_PHONE} {FULL_PHONE}' />"
|
||||
f"<node bounds='[0,540][1080,2400]' text='{SAFE_TEXT}' />"
|
||||
f"<node bounds='[0,540][1080,2376]' text='{SAFE_TEXT}' />"
|
||||
"</hierarchy>"
|
||||
)
|
||||
|
||||
@@ -117,17 +117,17 @@ class SkuEvidenceSanitizerTests(unittest.TestCase):
|
||||
self.assertNotIn(MASKED_PHONE, derived_xml)
|
||||
self.assertIn(f'"human_declared_state": "{state}"', manifest)
|
||||
self.assertIn('"privacy_tier": "SANITIZED"', manifest)
|
||||
self.assertIn('"sanitizer_version": "t103-privacy-v2"', manifest)
|
||||
self.assertIn('"sanitizer_version": "t103-privacy-v3"', manifest)
|
||||
self.assertIn('"screenshot_space": {', manifest)
|
||||
self.assertIn('"xml_coordinate_space": {', manifest)
|
||||
self.assertIn('"height": 2376', manifest)
|
||||
self.assertIn('"height": 2400', manifest)
|
||||
self.assertIn('"height": 2376', manifest)
|
||||
self.assertIn('"privacy_mask_rectangle": [', manifest)
|
||||
self.assertIn('"removed_nodes": 1', manifest)
|
||||
self.assertIn('"cleared_crossing_nodes": 0', manifest)
|
||||
self.assertIn('"retained_below_nodes": 1', manifest)
|
||||
self.assertIn('"max_right": 1080', manifest)
|
||||
self.assertIn('"max_bottom": 2400', manifest)
|
||||
self.assertIn('"max_bottom": 2376', manifest)
|
||||
self.assertNotIn("canonical_url", manifest)
|
||||
self.assertNotIn(TEST_SERIAL, manifest)
|
||||
self.assertNotIn("serial", manifest)
|
||||
@@ -138,9 +138,9 @@ class SkuEvidenceSanitizerTests(unittest.TestCase):
|
||||
def test_crossing_container_keeps_lower_children_but_clears_its_text(self) -> None:
|
||||
xml = (
|
||||
"<hierarchy>"
|
||||
f"<node bounds='[0,0][1080,2400]' text='{TEST_ADDRESS}' content-desc='{MASKED_PHONE}'>"
|
||||
f"<node bounds='[0,0][1080,2376]' text='{TEST_ADDRESS}' content-desc='{MASKED_PHONE}'>"
|
||||
f"<node bounds='[0,0][1080,540]' text='{FULL_PHONE}' />"
|
||||
f"<node bounds='[0,540][1080,2400]' text='{SAFE_TEXT}' />"
|
||||
f"<node bounds='[0,540][1080,2376]' text='{SAFE_TEXT}' />"
|
||||
"</node></hierarchy>"
|
||||
)
|
||||
with TemporaryDirectory() as temporary:
|
||||
@@ -151,7 +151,7 @@ class SkuEvidenceSanitizerTests(unittest.TestCase):
|
||||
|
||||
self.assertIsNotNone(crossing)
|
||||
assert crossing is not None
|
||||
self.assertEqual(crossing.attrib, {"bounds": "[0,0][1080,2400]"})
|
||||
self.assertEqual(crossing.attrib, {"bounds": "[0,0][1080,2376]"})
|
||||
self.assertEqual(len(list(crossing)), 1)
|
||||
self.assertEqual(list(crossing)[0].get("text"), SAFE_TEXT)
|
||||
manifest = json.loads(result.manifest_path.read_text(encoding="utf-8"))
|
||||
@@ -162,7 +162,7 @@ class SkuEvidenceSanitizerTests(unittest.TestCase):
|
||||
"cleared_crossing_nodes": 1,
|
||||
"retained_below_nodes": 1,
|
||||
"max_right": 1080,
|
||||
"max_bottom": 2400,
|
||||
"max_bottom": 2376,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -195,9 +195,9 @@ class SkuEvidenceSanitizerTests(unittest.TestCase):
|
||||
manifest["xml_coordinate_space"],
|
||||
{
|
||||
"width": 1080,
|
||||
"height": 2400,
|
||||
"height": 2376,
|
||||
"privacy_mask_rectangle": [0, 0, 1080, 540],
|
||||
"observed_max": {"right": 1080, "bottom": 2400},
|
||||
"observed_max": {"right": 1080, "bottom": 2376},
|
||||
},
|
||||
)
|
||||
|
||||
@@ -243,10 +243,10 @@ class SkuEvidenceSanitizerTests(unittest.TestCase):
|
||||
("bounds", "<hierarchy><node text='missing bounds' /></hierarchy>"),
|
||||
(
|
||||
"private-parent-with-lower-child",
|
||||
"<hierarchy><node bounds='[0,0][1080,540]'><node bounds='[0,540][1080,2400]' text='x' /></node></hierarchy>",
|
||||
"<hierarchy><node bounds='[0,0][1080,540]'><node bounds='[0,540][1080,2376]' text='x' /></node></hierarchy>",
|
||||
),
|
||||
("full-phone-below", f"<hierarchy><node bounds='[0,540][1080,2400]' text='{FULL_PHONE}' /></hierarchy>"),
|
||||
("masked-phone-below", f"<hierarchy><node bounds='[0,540][1080,2400]' text='{MASKED_PHONE}' /></hierarchy>"),
|
||||
("full-phone-below", f"<hierarchy><node bounds='[0,540][1080,2376]' text='{FULL_PHONE}' /></hierarchy>"),
|
||||
("masked-phone-below", f"<hierarchy><node bounds='[0,540][1080,2376]' text='{MASKED_PHONE}' /></hierarchy>"),
|
||||
)
|
||||
for kind, xml in malformed:
|
||||
with self.subTest(kind=kind), TemporaryDirectory() as temporary:
|
||||
@@ -281,7 +281,7 @@ class SkuEvidenceSanitizerTests(unittest.TestCase):
|
||||
xml = (
|
||||
"<hierarchy>"
|
||||
"<node bounds='[0,0][1080,540]' text='private' />"
|
||||
f"<node bounds='[0,540][1080,2400]' text='{value}' />"
|
||||
f"<node bounds='[0,540][1080,2376]' text='{value}' />"
|
||||
"</hierarchy>"
|
||||
)
|
||||
with self.subTest(value=value), TemporaryDirectory() as temporary:
|
||||
@@ -294,7 +294,7 @@ class SkuEvidenceSanitizerTests(unittest.TestCase):
|
||||
"<hierarchy>"
|
||||
"<node bounds='[0,0][1080,540]' text='private' />"
|
||||
"<node bounds='[0,540][1080,1000]' text='138' content-desc='0013' />"
|
||||
"<node bounds='[0,1000][1080,2400]' text='8000' />"
|
||||
"<node bounds='[0,1000][1080,2376]' text='8000' />"
|
||||
"</hierarchy>"
|
||||
)
|
||||
with TemporaryDirectory() as temporary:
|
||||
@@ -305,7 +305,7 @@ class SkuEvidenceSanitizerTests(unittest.TestCase):
|
||||
|
||||
def test_privacy_geometry_requires_removed_and_retained_nodes(self) -> None:
|
||||
scenarios = (
|
||||
("no-private", f"<hierarchy><node bounds='[0,540][1080,2400]' text='{SAFE_TEXT}' /></hierarchy>"),
|
||||
("no-private", f"<hierarchy><node bounds='[0,540][1080,2376]' text='{SAFE_TEXT}' /></hierarchy>"),
|
||||
("no-below", "<hierarchy><node bounds='[0,0][1080,540]' text='private' /></hierarchy>"),
|
||||
)
|
||||
for name, xml in scenarios:
|
||||
@@ -321,26 +321,26 @@ class SkuEvidenceSanitizerTests(unittest.TestCase):
|
||||
(
|
||||
"short-width",
|
||||
"<hierarchy><node bounds='[0,0][1079,540]' text='private' />"
|
||||
"<node bounds='[0,540][1079,2400]' text='safe' /></hierarchy>",
|
||||
"1079x2400",
|
||||
"<node bounds='[0,540][1079,2376]' text='safe' /></hierarchy>",
|
||||
"1079x2376",
|
||||
),
|
||||
(
|
||||
"short-height",
|
||||
"<hierarchy><node bounds='[0,0][1080,540]' text='private' />"
|
||||
"<node bounds='[0,540][1080,2376]' text='safe' /></hierarchy>",
|
||||
"1080x2376",
|
||||
"<node bounds='[0,540][1080,2375]' text='safe' /></hierarchy>",
|
||||
"1080x2375",
|
||||
),
|
||||
(
|
||||
"wide-width",
|
||||
"<hierarchy><node bounds='[0,0][1081,540]' text='private' />"
|
||||
"<node bounds='[0,540][1081,2400]' text='safe' /></hierarchy>",
|
||||
"1081x2400",
|
||||
"<node bounds='[0,540][1081,2376]' text='safe' /></hierarchy>",
|
||||
"1081x2376",
|
||||
),
|
||||
(
|
||||
"tall-height",
|
||||
"old-v2-xml-height",
|
||||
"<hierarchy><node bounds='[0,0][1080,540]' text='private' />"
|
||||
"<node bounds='[0,540][1080,2401]' text='safe' /></hierarchy>",
|
||||
"1080x2401",
|
||||
"<node bounds='[0,540][1080,2400]' text='safe' /></hierarchy>",
|
||||
"1080x2400",
|
||||
),
|
||||
)
|
||||
for name, xml, observed in scenarios:
|
||||
|
||||
@@ -154,8 +154,10 @@ PDD 规格面板不可避免显示收货区域和掩码手机号。原始截图/
|
||||
T-103 已在 `client/src/cmbuyer_client/device/sku_evidence_sanitizer.py` 实现本机确定性脱敏器,并由
|
||||
`client/scripts/sanitize_sku_panel_evidence.py` 提供离线 CLI。第一组新 raw 的 PNG 头部由人确认实际为
|
||||
1080×2376,推翻了 v1 将截图和 XML 坐标空间都写成 1080×2400 的假设;v1 正确拒绝且原始证据未重采。
|
||||
当前 `t103-privacy-v2` 配置精确绑定 PKG110 / Android 16 / 拼多多 8.17.0 / goods_id
|
||||
`937122477375`,分别约束 screenshot space=1080×2376、XML coordinate space=1080×2400,二者都把
|
||||
随后 v2 在同一份 raw 上安全报告 XML `observed 1080x2376` 并拒绝发布,证明其独立配置的
|
||||
1080×2400 假设同样不成立。当前 `t103-privacy-v3` 配置精确绑定 PKG110 / Android 16 / 拼多多
|
||||
8.17.0 / goods_id `937122477375`;screenshot space 与 XML coordinate space 仍分别建模、分别校验,
|
||||
当前都精确为 1080×2376,且都把
|
||||
`[0,0,1080,540)` 作为整宽隐私带。截图覆盖该区域;XML 递归移除区域内节点,跨界容器只清空自身
|
||||
敏感属性并保留下方子节点。地址依靠已确认的整块几何隔离而不是易漏的关键词表;完整、掩码、带分隔符
|
||||
或跨节点手机号残留会被自动复检拒绝。
|
||||
@@ -165,7 +167,7 @@ T-103 已在 `client/src/cmbuyer_client/device/sku_evidence_sanitizer.py` 实现
|
||||
```
|
||||
|
||||
脱敏器校验源 manifest 与文件哈希、设备/App/商品/人工状态、截图分辨率和 XML 隐私结构;XML 所有
|
||||
节点观察到的最大 right/bottom 必须精确为 1080×2400,否则只报告非敏感 observed 尺寸并拒绝。它只允许发布到
|
||||
节点观察到的最大 right/bottom 必须精确为 1080×2376,否则只报告非敏感 observed 尺寸并拒绝。它只允许发布到
|
||||
同级且尚不存在的 `derived`;失败或发布竞态不覆盖已有目录、不留下 staging。派生 manifest 记录
|
||||
`privacy_tier=SANITIZED`、sanitizer 版本、两个坐标空间、清理计数及本机 source/derived 哈希,不记录
|
||||
原始路径、serial 或页面正文。只有自动复检通过并经人确认状态对应性的派生物,agent 才能读取并提取
|
||||
|
||||
@@ -33,8 +33,9 @@
|
||||
打开规格面板;T-110 已获项目所有者批准,只把该证据/版本绑定的精确唯一入口作为第一趟可逆导航,
|
||||
数量、确认页、提交订单、付款与通用点击能力仍不可达。T-103 的原始证据本机隔离与确定性脱敏器
|
||||
已完成离线实现;人工确认面板刚打开时目标颜色和尺码已经自动选中,取证三态已据此修正。下一步
|
||||
用 v2 对已采第一态 raw 重新脱敏并验证 XML 坐标空间,再采集“两个维度改为非目标 / 两个维度恢复
|
||||
目标”的 raw,由人只核对 derived。在派生证据验收前不写页面判据,Phase 2 仍不能抢跑。
|
||||
用 v3 对已采第一态 raw 重新脱敏;截图与 XML 已分别安全观测为 1080×2376,仍作为两个独立坐标
|
||||
空间严格校验。第一态 derived 经人验收后,再采集“两个维度改为非目标 / 两个维度恢复目标”的 raw,
|
||||
并由人只核对 derived。在派生证据验收前不写页面判据,Phase 2 仍不能抢跑。
|
||||
|
||||
## 当前目录要点
|
||||
|
||||
@@ -161,8 +162,9 @@ T-103 已确认当前衣服商品只能从精确文案“快要抢光”进入
|
||||
```
|
||||
|
||||
原始 screenshot/XML 可能包含 PDD 固定展示的地址和掩码手机号,只能留在本机 `raw` 目录,不能由
|
||||
agent、fixture、业务或上传端消费。`t103-privacy-v2` 分别固定截图 1080×2376 与 XML 坐标
|
||||
1080×2400,并校验源哈希、设备/App/商品/人工状态与隐私结构,在 sibling
|
||||
agent、fixture、业务或上传端消费。`t103-privacy-v3` 把截图与 XML 保持为两个独立坐标空间,
|
||||
并根据同一第一态 raw 的两次 fail-closed 安全观测将二者分别精确固定为 1080×2376;它校验源哈希、
|
||||
设备/App/商品/人工状态与隐私结构,在 sibling
|
||||
`derived` 目录原子发布 screenshot/XML 与 manifest;任何不匹配、手机号残留或已有目标均拒绝发布。
|
||||
自动复检通过且人确认三态对应性后,agent 才能读取派生物并提取最小 fixture、编写判据。
|
||||
人工确认中还必须记录中间态实际选择的非目标颜色和尺码,不能只写“已切换”。
|
||||
|
||||
+9
-1
@@ -25,7 +25,7 @@ write_paths:
|
||||
- docs/current-state.md
|
||||
---
|
||||
|
||||
<!-- BEGIN VIKUNJA EXPORT id=23 synced=2026-08-04T03:59:02Z sha256=07472f92450a4ec3e062f779461c29a40f0078b17a6d58745e529f0c855a64cf -->
|
||||
<!-- BEGIN VIKUNJA EXPORT id=23 synced=2026-08-04T06:06:05Z sha256=9de2a35beba4cca7a29cf4dc6b5ff643d829f6467ff576da976589a8d1f3dcad -->
|
||||
## 问题 / 背景
|
||||
|
||||
T-102 已证明 canonical 链接可进入目标商品。T-103 随后在 PKG110 / Android 16 / 拼多多 8.17.0、衣服商品 goods_id `937122477375` 上确认:规格面板只能从详情页右下角精确文案“快要抢光”进入,面板固定显示收货区域和掩码手机号。T-110 经项目所有者批准,将该已取证点击定义为可逆、能力受限的规格面板导航;这不是通用购买入口豁免,不授权其他文案、数量、确认页、提交订单或支付。 项目所有者随后确认,面板刚打开时已自动选中目标颜色“黑色CHA(纯棉)”和尺码“M(建议100-115)”;因此本任务不再假设存在“未选择”或“只选择一个维度”的初始状态。
|
||||
@@ -123,6 +123,14 @@ T-103 新三态离线实现与主审:提交 dbb69a7 将人工声明状态集
|
||||
### 2026-08-04T03:58:54Z · ila
|
||||
|
||||
T-103 sanitizer v2 坐标修正与主审:提交 44c027a 将 screenshot space 固定为人确认的 1080x2376,并把 XML coordinate space 独立严格配置为待验证的 1080x2400;sanitizer_version 升为 t103-privacy-v2。XML 会统计所有 bounds 的 max right/bottom,任何小于或大于配置的偏差均 fail closed,错误只含非敏感 observed 尺寸。派生 manifest 记录两个坐标空间和各自遮罩。主 agent 独立复跑 69 项 client 单测、compileall、CLI help 与 diff-check,全部通过;未读取真实 raw 正文、未连接设备。等待人用同一第一态 raw 重跑 v2 脱敏。
|
||||
|
||||
### 2026-08-04T06:01:02Z · ila
|
||||
|
||||
人使用 sanitizer v2 对同一第一态 raw 重跑,安全诊断返回 XML observed 1080x2376;未发布 derived。由此确认本次 screenshot space 与 XML coordinate space 均为 1080x2376,v2 对 XML=1080x2400 的待验证假设被真机证据否定。原始证据继续保留且不重采;下一步升级 v3,仍分离建模两个空间但分别精确绑定当前相同尺寸。
|
||||
|
||||
### 2026-08-04T06:05:53Z · ila
|
||||
|
||||
2026-08-04 T-103 sanitizer v3 坐标修正与主审:人用同一第一态 raw 运行 v2,脱敏器安全拒绝并仅报告 observed 1080x2376,证明 XML 实际坐标与截图相同;原始证据仍有效、未重采、未读取正文。提交 acf7e11 将 sanitizer_version 升为 t103-privacy-v3;截图与 XML 仍分别建模并分别严格校验,但当前均精确绑定 1080x2376,隐私带保持 [0,0,1080,540)。合成测试明确拒绝旧截图 1080x2400、旧 v2 XML 1080x2400,以及较小/较大坐标;手机号残留、哈希/状态/版本、确定性、原子发布和不覆盖门禁保持不变。主 agent 独立复跑 69 项 client 单测、compileall、CLI help、静态禁用能力检索与 diff-check,全部通过;未连接设备、未读取真实 raw。T-103 保持 DOING,等待人用同一第一态 raw 重跑 v3 并只核对 derived。
|
||||
<!-- END VIKUNJA EXPORT -->
|
||||
|
||||
## 边界
|
||||
|
||||
Reference in New Issue
Block a user