Fix facts registry commands and make precheck parsing escape-aware
ci / svc-realcombo (pull_request) Successful in 1m59s
ci / test (pull_request) Successful in 5m13s
ci / test-pg (pull_request) Successful in 8m6s

Why: F2 token extraction predates the two-section (HOME/IMC) layout of
~/.secrets/gitea so it concatenated both tokens and always failed; F6
registered a grep BRE alternation that facts-verify unescapes into a
literal pipe, failing re-verification and misaligning precheck's naive
pipe split into a spurious F6 date-format expiry warning, while both
underlying facts still hold.

Evidence: make facts-verify now 6/6 PASS with last_verified refreshed
to 2026-10-14; new regression test for escaped pipes in facts rows;
full governance suite 342 tests OK (18 skipped); precheck [facts] line
reports all facts fresh on the fixed parser.

Impact: policy/facts.md F2 (HOME-section awk extraction) and F6
(negated pipe-free grep); scripts/task.sh precheck neutralizes escaped
pipes the same way facts-verify does; tests/test_task.py covers it.

Refs: precheck WARN 过期事实 F6(日期格式); AGENTS.md 证据与验证门禁.
This commit is contained in:
2026-10-14 06:13:51 +00:00
parent 427e9faf47
commit 3b0e100fba
3 changed files with 25 additions and 7 deletions
+15
View File
@@ -120,6 +120,21 @@ class TaskLifecycleTests(unittest.TestCase):
reading = next(line for line in result.stdout.splitlines() if line.startswith("[required-reading]"))
self.assertIn("policy/delivery.md", reading)
def test_precheck_facts_row_with_escaped_pipe_stays_fresh(self):
facts = self.repo / "policy/facts.md"
facts.parent.mkdir(exist_ok=True)
facts.write_text(
"| ID | 事实 | 验证命令 | last_verified | TTL(天) |\n"
"|---|---|---|---|---|\n"
"| F1 | 含转义竖线的验证命令 | `echo a\\|b` | 2026-10-13 | 9999 |\n"
)
self.git(self.repo, "add", "policy")
self.git(self.repo, "commit", "-m", "Add facts registry with escaped pipe")
result = self.task(self.repo, "precheck")
line = next(l for l in result.stdout.splitlines() if l.startswith("[facts]"))
self.assertIn("均在有效期内", line)
self.assertNotIn("日期格式", line)
def test_sync_same_base_preserves_head_and_card(self):
wt = self.worktree()
card = self.record_task_card(wt)