80000x · 04 — Review / approval checklist (R0-R11, decision template)
04 — Review / approval checklist
Audience: the operator (or DOT review function) deciding whether a
cut_manifestis ready for CUT.
The reviewer's job is to catch the things the Agent could not catch by re-reading its own output: source mis-attribution, boundary errors, Axis B drift, parent-child confusion. The CUT stage refuses to run without an approval record produced by this checklist.
1. Inputs to the review
- The manifest JSON (path: KB or local scratch).
- The
mark_report.md. - The current source (re-fetched at review time).
- The substrate vocab (live DB if available; otherwise the snapshot in
02 §6).
2. Mandatory checks
Run them in order. Stop at the first FAIL; record it; route back to the Agent.
R0 — Manifest format
-
manifest_format_versionis supported ("1.0"at time of this package). -
manifest_digestis present and recomputes to the same value. -
manifest_idis unique within the KB (no prior approved manifest re-using this id). -
approval.status == "pending"at intake. (Notapproved— that means the Agent forged the approval.)
R1 — Source identity
-
source.url_or_fileis what the user requested (compare with the original user message). - Fresh fetch of the URL returns a body whose
sha256matchessource.source_hash. If the source has moved/changed, document and decide whether a re-MARK is needed. -
source.retrieved_atis within the freshness window (≤ 24 h by default).
R2 — Article boundary
For each articles[] entry:
-
article_labelis one the user requested (no extra articles, no fewer). -
boundary.start_quoteappears verbatim at the article's start in the source. -
boundary.end_quoteappears verbatim at the article's end (or right before the next article header / EOF). - Nothing before
start_quotewas included in any piece. - Nothing after
end_quotewas included in any piece.
R3 — Piece count plausibility
- The piece count is not absurd. Rule of thumb: most legal articles produce 2–10 pieces (title + 1–8 clauses/sub-points). If the manifest has 1 piece or >20 pieces for a single article, scrutinize.
- Every clause/numbered paragraph in the source appears as a piece. No clause silently absorbed into a sibling.
R4 — Axis A (source order)
-
source_positionis dense (1..N, no gaps). -
source_positionis monotonic (strictly increasing). -
source_positionis unique within the article. - Sorted concat matches the article body's normalized form (reconstruction preview byte-equal — see R6).
R5 — Axis B (professional)
- Every piece has
axis_b.unit_kindin{design_doc_section, law_unit}. - Every piece has
axis_b.section_typein the live substrate vocab. - Every piece has
axis_b.legal_documentset OR a flag explaining absence. -
professional_tags[]are not invented — each tag is either obvious from the source or empty. - No second source of truth: Axis B never duplicates a value the substrate already encodes elsewhere.
R6 — Axis C (parent / child / grandchild)
- Exactly one piece has
parent_local_piece_id = nullper article (the title / root). - Every other piece's
parent_local_piece_idresolves to a piece in the same article. -
depthvalues are consistent:depth(p) == depth(parent(p)) + 1. - Max depth ≤ 2 (root → clause → sub-point). Deeper than 2 is allowed only with explicit reviewer sign-off and an
uncertainty_flag. - No cycles in the parent graph.
R7 — Reconstruction preview
-
reconstruction.expected_digestequals each article'soriginal_text_hash. -
reconstruction.preview(first 400 chars) reads like the start of the article when eyeballed. -
reconstruction.rerun_byte_identicalistrue.
R8 — Uncertainty flags
- Every
uncertainty_flags[]entry is either:- explicitly resolved (reviewer writes a one-line decision next to it), OR
- downgraded to "operator-accepted" (acceptable to ship), OR
- escalated back to Agent for a re-MARK.
- No flag is silently ignored.
R9 — Corpus uniqueness
-
doc_codeis unique in the existing IU corpus (no priorinformation_unit.canonical_addressstarts with the same prefix unless this is an explicit version update). - No piece's
text_hashalready exists in an enacted IU (duplicate-cut guard). If a duplicate exists, flag it and decide whether to re-use the existing IU instead of minting a new one.
R10 — Substrate vocab freshness
-
unit_kind,section_type,piece_role,link_rolevalues are in the live DB vocab at review time (not just the snapshot). Verify with:
SELECT pg_get_constraintdef(c.oid)
FROM pg_constraint c
JOIN pg_class t ON c.conrelid = t.oid
WHERE t.relname = 'information_unit' AND c.contype = 'c';
-- and similar for iu_sql_link.link_role
If vocab has drifted, recommend a re-MARK with the updated terms.
R11 — No forbidden side effects observed
- No
cut_recordalready filled in (must benullat REVIEW time). - No
verify_recordalready filled in. - No
iu_ids_created[]claimed. - No
dot_command_run_idset.
If any are present, the Agent cheated and self-advanced. Reject and re-MARK.
3. Decision
If all R0–R11 PASS:
approval:
status: approved
approved_by: <operator-handle@org or DOT identity>
approved_at: <ISO-8601 UTC, current>
approval_doc_id: <KB doc id of this review record>
rejection_reason: null
Re-upload the manifest to a stable, immutable KB path:
knowledge/dev/laws/<doc-folder>/approved-manifests/<manifest_id>.json
The CUT stage will read from this exact path.
Else:
approval:
status: rejected
approved_by: null
approved_at: null
approval_doc_id: null
rejection_reason: "<one-line summary; full detail in the review report>"
Send back to the Agent with the failed check labels (e.g., "R4 source_position has a gap at lp-004"). The Agent re-runs MARK; loop.
4. Review report template
Save under knowledge/dev/laws/<doc-folder>/mark-reviews/<UTC-timestamp>-<manifest_id>.md:
# Review of manifest <manifest_id>
- Reviewer: <handle>
- Reviewed at: <UTC>
- Manifest digest: <sha256>
- Articles: <N> (Điều 37, 38, 39)
## Checks
| Check | Result | Note |
|-------|--------|------|
| R0 format | PASS | |
| R1 source identity | PASS | re-fetched, hash match |
| R2 boundary | PASS | |
| R3 piece plausibility | PASS | 4 pieces per article, all clauses present |
| R4 Axis A | PASS | 1..N dense |
| R5 Axis B | PASS | unit_kind=law_unit, section_type all valid |
| R6 Axis C | PASS | depth max=2 |
| R7 reconstruction | PASS | byte-equal |
| R8 uncertainty | PASS | flags empty |
| R9 corpus uniqueness | PASS | no duplicates |
| R10 vocab freshness | PASS | verified live |
| R11 no forbidden side effects | PASS | cut_record/verify_record null |
## Decision
APPROVED. Next: CUT via `dot_iu_cut_from_manifest --manifest <path> --approval-doc-id <this-doc-id>`.
5. Authority
A reviewer must be authorized to approve manifests for the relevant doc_code. The KB stores an iu_core_approval_authority registry mapping operator identities to allowed doc_code prefixes. If the registry is absent, default to the team's standing operator (user) until the registry is populated.