Repository navigation
34 backfilled contracts carry a legal_owner, and is_backfilled says on the same row that no review ever happened #53
Description
Found while measuring #47.
Measured
claude/issue-47-seed-legal-owner, from the compiled artifact:
contracts with a legal_owner 68
of those, is_backfilled = true 34
of those 34, review_started_at null (all 34)
So a third of the corpus carries a named lawyer on a row that also says, in its own columns, that nobody ever reviewed it.
The contradiction, in the declarations' own words
clm_contract.legal_owner,src/objects/contract.object.ts: description "The lawyer who accepted the review. Required before a submitted contract enters review."clm_contract.is_backfilled, DESIGN.md §13 Q8: 补录的已签合同 — an already-executed contract entered after the fact, which starts active and skipped review and approval.src/data/plan-contracts.tssays the same at length: the backfilled population "claims nothing they do not have … nosubmitted_at, noreview_started_at, noapproved_at, no review, no deviation and no signature round".- F16 (
executed_upload) is the action that produces such a contract in the running app, and it assigns no legal owner.
The fixture's rule is hasLegalOwner = pastSubmission && type.requiresLegalReview && status !== 'submitted', which does not consult backfilled. That is why the two claims sit on the same row.
The two readings, and what each costs
- A.
legal_ownermeans "the lawyer who accepted the review". Then a backfilled contract must not carry one, andhasLegalOwnergains&& !backfilled.⚠️ Cost, and it is real: DESIGN.md §10 draws the expiring corpus from the backfilled contracts, so those 34 rows are precisely F12renewal_noticeand F13expiration_sweep's population. Both copylegal_ownerbesideowner_id, so every renewal and expiry notice would drop from two recipients to one — the opposite direction from The demo makes M3's reminder layer look broken: 54 of 120 contracts have nolegal_owner, so four of six scheduled jobs notify nobody #47. - B.
legal_ownermeans "the lawyer who owns this file in legal". Then the data is right and the field description is what is wrong, and it should say so — custodianship, with the review-acceptance sentence demoted to how the column is normally first written.
B is the cheaper answer and, for a records-keeping product, arguably the truer one: a backfilled contract still has somebody in legal responsible for it. But that is a product decision about what a column means, not a developer's, and either way something has to change so the row stops asserting both.
Not urgent, and ⛔ not a rider
Nothing measured is broken: no gate, no flow and no screen misbehaves. It is on the "places the product lies" list from #45 — a column that says one thing while the column next to it says the opposite — which is why it is filed rather than left in a PR body.
Related
#47 (where this was measured; it deals this column but deliberately does not change WHICH rows carry it) · #39 / PR #42 (F12/F13, and F16 which creates backfilled contracts) · #45 (the dogfood pass and its "places the product lies" category) · DESIGN.md §13 Q8
Activity
zhuangjianguo commentedon Sep 10, 2026
维护者速读
事情:三分之一的种子合同(34 份补录合同)上写着一位「法务负责人」,而同一行的另一列说这份合同从来没有被审查过。两句话不可能都对。
为什么会这样:
legal_owner的字段说明写的是**「接受了审查的那位律师」。而补录合同(is_backfilled)按设计是已经签好、事后录入、跳过审查与审批**的 —— 它们没有review_started_at、没有审查记录、没有签署轮次。种子在分配legal_owner时没有看backfilled这一列,于是两个声明落到了同一行上。你要做的:回一个字母,A 或 B。
legal_owner就是「接受审查的律师」⇒ 补录合同不该有,种子加一条&& !backfilledlegal_owner⇒ 每一条续签与到期通知从两个收件人掉到一个 —— 与 #47 刚做的事方向相反legal_owner是「法务这边归口负责这份档案的人」⇒ 数据是对的,错的是字段说明,改说明业务含义直译
A = 「律师」这个栏位专指审过这份合同的人,没审过就该空着;B = 那是这份档案在法务的归口人,合同怎么进来的不影响谁负责它。
四棱分析
os-decision-facets
① 项目长远合理性 — 偏 B。对一个档案管理型产品来说,一份合同在它整个生命周期里都该有法务归口人,而不只是在审查那一刻。选 A 之后,补录合同在法务侧无人负责 —— 而那恰恰是会到期、会需要续签决策的那一批。那是个架构上的洞,不只是少个收件人。
② 实际业务拉动 — 偏 B,且这一棱有实测。F12/F13 今天就在抄送
legal_owner,#47 刚测过收件人从 5 人变 7 人。选 A 会让续签与到期通知倒退回单收件人,方向与刚落地的改进相反。③ 防 AI 犯错 —⚠️ 这一棱内部打架,必须说破。仓规是「协议为基准:spec 与代码不一致默认改代码对齐」,照字面指向 A(改数据去迁就已声明的说明)。但那条规矩预设了声明是对的;这张卡问的正是那句说明是不是从一开始就写窄了。往深一层看:B 之后
legal_owner在 F12/F13 里被正确使用;A 之后那两个流程会去抄一个经常为空的列 —— 让下一个作者以为「抄了就有收件人」。所以字面规矩指 A,防错的实质指 B。⛔ 我不替你在这两者之间选。④ 创业阶段不扩散 — 偏 B。B 改一句话。A 改种子逻辑、丢收件人,还要重新论证 §10 的到期语料从哪来。
推荐:B,并要求同批把字段说明改成「法务归口人」并把「审查时首次写入」降格为一句用法说明。回退:选 A 就要一并接受 F12/F13 退回单收件人,并说明 §10 的到期语料改从哪里抽。
⛔ 本分析看不见什么:你们真实法务流程里,补录进来的旧合同有没有人接手。如果现实里就是没人管,A 才是诚实的;如果有归口人,B 是。这一个事实定这张卡,而它只在你那里。
为什么这张不能自裁
「说明书脱节」那条自裁通道的前提是实现没被裁错。这里恰恰相反:实现是对是错,正是待裁的那个问题 —— B 说数据对、说明错;A 说说明对、数据错。⛔ 通道够不到。而且它动的是已发布的字段说明,属公开契约语义。
不阻塞任何在飞卡。
关联
#47(发现处,已合并
d34b225;它刻意只分配这一列、不改哪些行携带它)· #39 / PR #42(F12/F13 与创建补录合同的 F16)· #45(「产品说谎的地方」那一类)·DESIGN.md§13 Q8、§10Generated by Claude Code