Commit 3e2f734
task-1(v3.0): the record can finally say which diff it covers
Spec §C says the triage record binds session_id, base_commit and
declared_paths, and the Stop-hook rule task-8 landed reads exactly those to
decide whether a record covers the current diff. The schema is
additionalProperties:false and carried none of them, so no record could express
them and no record could ever cover anything. The gate is off by default, so
nothing was broken — Feature C would simply have shipped inert, a correct
mechanism with nothing to feed it.
WHY each field is shaped the way it is:
* `session_id` is optional and nullable, never required. This engine never sees
a session; only /v:triage does. Requiring it would invalidate every record the
scorer writes outside a triage command. Absent or null means the record binds
no session and therefore covers nothing, which is the fail-closed direction the
gate's exact-match test already produces. The EMPTY STRING is rejected: it
looks like a binding and can never match, and that is the one shape that
misleads a reader.
* `declared_paths` items are constrained to what the consumer can actually read.
The hook serializes candidates as `tier<US>run_id<US>path` and DROPS any entry
containing U+001F, LF or CR. Dropping narrows the declared set, which is safe
for the gate but silent for the producer — so the schema rejects every C0
control character here, where the producer still finds out. Absolute paths and
`..` segments are rejected for the same reason: git never reports either, so
such an entry could only ever match nothing while looking like coverage.
* `base_commit` is expressible and deliberately inert. task-8 reads it and
derives no freshness rule, because HEAD legitimately advances mid-session —
/v:triage's own commit of the record moves it — so a mismatch is not evidence
of staleness. The description says so, and says not to add such a rule without
evidence that a mismatch correlates with a bad decision.
* `tier` is added and PINNED to `decision` by three conditionals. The hook
prefers `.tier` over `.decision` when present, so an unconstrained `tier` would
be a second, higher-priority source of truth for a safety-relevant
classification: a record could say FULL_PIPELINE and wear `tier: DIRECT` and be
exempted as the auto-route class. Pinned, the hook's preferred branch is
provably identical to its fallback instead of a way around it. This is the same
hazard as override #4 one layer up, and it gets the same answer — make the
disagreement unrepresentable rather than trusted.
* `build_record` gains an optional `binding` kwarg, and it is a footgun removal
rather than a convenience. `digest` covers the whole record, so a producer that
attached these fields after building would ship a record whose self-integrity
digest silently no longer verifies — silently, because `digest` is optional and
checked only when present. The kwarg folds the binding in before the digest is
taken. It does NOT accept `tier`: that is derived from the decision, so the
producer cannot introduce the disagreement the schema forbids. Without a
binding the record is byte-for-byte and digest-for-digest what it was.
Verified against the consumer, not just asserted: the hook's own `_TRIAGE_JQ`
was extracted verbatim and run over records built to this schema. All three
decisions map to DIRECT/SCOPED/FULL, a record carrying explicit `tier` produces
output identical to its decision-only twin, and a foreign-session record emits
nothing.
Selftests: preeval 131 -> 174 cases. Covers tier agreement and disagreement for
all three decisions, session_id null/absent/empty, base_commit shapes, the three
declared-path forms the gate understands, twelve rejected path shapes including
the separator and line breaks it would otherwise drop, and the digest staying
correct through build_record while breaking when bolted on afterwards.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>1 parent 3b14a7e commit 3e2f734
2 files changed
Lines changed: 203 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
47 | 77 | | |
48 | 78 | | |
49 | 79 | | |
| |||
99 | 129 | | |
100 | 130 | | |
101 | 131 | | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
102 | 155 | | |
103 | 156 | | |
104 | 157 | | |
| |||
111 | 164 | | |
112 | 165 | | |
113 | 166 | | |
114 | | - | |
| 167 | + | |
115 | 168 | | |
116 | 169 | | |
117 | 170 | | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
118 | 178 | | |
119 | 179 | | |
120 | 180 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
701 | 701 | | |
702 | 702 | | |
703 | 703 | | |
704 | | - | |
| 704 | + | |
705 | 705 | | |
706 | | - | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
| 717 | + | |
| 718 | + | |
| 719 | + | |
| 720 | + | |
| 721 | + | |
| 722 | + | |
| 723 | + | |
| 724 | + | |
| 725 | + | |
| 726 | + | |
707 | 727 | | |
708 | 728 | | |
709 | 729 | | |
| |||
723 | 743 | | |
724 | 744 | | |
725 | 745 | | |
| 746 | + | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
726 | 758 | | |
727 | 759 | | |
728 | 760 | | |
| |||
1559 | 1591 | | |
1560 | 1592 | | |
1561 | 1593 | | |
| 1594 | + | |
| 1595 | + | |
| 1596 | + | |
| 1597 | + | |
| 1598 | + | |
| 1599 | + | |
| 1600 | + | |
| 1601 | + | |
| 1602 | + | |
| 1603 | + | |
| 1604 | + | |
| 1605 | + | |
| 1606 | + | |
| 1607 | + | |
| 1608 | + | |
| 1609 | + | |
| 1610 | + | |
| 1611 | + | |
| 1612 | + | |
| 1613 | + | |
| 1614 | + | |
| 1615 | + | |
| 1616 | + | |
| 1617 | + | |
| 1618 | + | |
| 1619 | + | |
| 1620 | + | |
| 1621 | + | |
| 1622 | + | |
| 1623 | + | |
| 1624 | + | |
| 1625 | + | |
| 1626 | + | |
| 1627 | + | |
| 1628 | + | |
| 1629 | + | |
| 1630 | + | |
| 1631 | + | |
| 1632 | + | |
| 1633 | + | |
| 1634 | + | |
| 1635 | + | |
| 1636 | + | |
| 1637 | + | |
| 1638 | + | |
| 1639 | + | |
| 1640 | + | |
| 1641 | + | |
| 1642 | + | |
| 1643 | + | |
| 1644 | + | |
| 1645 | + | |
| 1646 | + | |
| 1647 | + | |
| 1648 | + | |
| 1649 | + | |
| 1650 | + | |
| 1651 | + | |
| 1652 | + | |
| 1653 | + | |
| 1654 | + | |
| 1655 | + | |
| 1656 | + | |
| 1657 | + | |
| 1658 | + | |
| 1659 | + | |
| 1660 | + | |
| 1661 | + | |
| 1662 | + | |
| 1663 | + | |
| 1664 | + | |
| 1665 | + | |
| 1666 | + | |
| 1667 | + | |
| 1668 | + | |
| 1669 | + | |
| 1670 | + | |
| 1671 | + | |
| 1672 | + | |
| 1673 | + | |
| 1674 | + | |
| 1675 | + | |
| 1676 | + | |
| 1677 | + | |
| 1678 | + | |
| 1679 | + | |
| 1680 | + | |
| 1681 | + | |
| 1682 | + | |
| 1683 | + | |
| 1684 | + | |
| 1685 | + | |
| 1686 | + | |
| 1687 | + | |
| 1688 | + | |
| 1689 | + | |
| 1690 | + | |
| 1691 | + | |
| 1692 | + | |
| 1693 | + | |
| 1694 | + | |
| 1695 | + | |
| 1696 | + | |
| 1697 | + | |
| 1698 | + | |
| 1699 | + | |
| 1700 | + | |
| 1701 | + | |
1562 | 1702 | | |
1563 | 1703 | | |
1564 | 1704 | | |
| |||
0 commit comments