diff --git a/.claude/skills/pm-dispatch/references/contract-review.md b/.claude/skills/pm-dispatch/references/contract-review.md index b439e6c980f..28bc6e0c4c8 100644 --- a/.claude/skills/pm-dispatch/references/contract-review.md +++ b/.claude/skills/pm-dispatch/references/contract-review.md @@ -18,6 +18,8 @@ - 已发布面以包的 `exports` 映射为准:从入口类型图不可达、且 `exports` 不可寻址的 `.d.ts` 是 出货字节,⛔ 不是已发布接受集,改它不触发 `Clause-②: yes`;legacy node10 深引用在契约之外。 - 四面皆不碰 ⇒ CI 加席位自读 ⛔ 不起第二个 agent;谁跑 = 派发席,达档者席内审。 +- 派发席达档调用被配额拒(HTTP 429)⇒ ⛔ 不降档审;PR 落交接行、留等复核标记,交分诊席。 +- `Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (, ) · head ` - 复核记录 = 一条评论落 PR 或卡,席内与子代理同形;散文、dev 自评、`os-dev-report` 恒不算。 - 同形 = `## Contract review` 题头、head sha 独占码段、①②③ 逐项(申报面外三面加 ④)、 独立性对、PASS/FAIL。 @@ -32,8 +34,6 @@ 被引代码读而不审;①–④ 合称完整复核,余面同形无 ④,⛔ 无第二条记录。 - 实质 head 各欠一轮完整复核;只落发现的 commit 由同一复核者 delta 复核;无 must-fix 即止。 - 另记作者:PR `user.login` 非 `objectstack-fleet[bot]` ⇒ ③ 注点名该 login(脱中继写),落地前读。 -- 复核形状:只读 diff 与卡片,check 结论取 head 的 check-runs,⛔ 永不本地重跑派生门禁族。 -- 只喂卡片、既有裁决与 PR 本体,⛔ 不喂派发令与派发席自己的结论;简报写成对抗性。 - 简报从 `node scripts/pm/record-recognisers.mjs --brief-template` 起稿: 只读条款与输入集内建,⛔ 不删 ⛔ 行。 - 隔离复核子代理暂存全写按所审 PR 命名的 `/pr-/`,⛔ 不读非本轮自写的暂存。 @@ -51,5 +51,5 @@ - 只作等复核标记,⛔ 不是闸门;单载体 = PR,卡上副本在规则外、不是要求。 - 挂:ACCEPT 时条款②任一肢命中而现 head 无同形 PASS 在案 ⇒ 派发席同笔挂于 PR。 - 摘:现 head 同形 PASS 在案 ⇒ 写记录的席同笔摘;PR 合并或关闭 ⇒ 派发席摘;FAIL 不摘。 -- 读者 = 维护者过滤 `is:pr is:open label:needs:contract-review` 与席位巡查、交接。 +- 只带标记无交接行者仍归本席,分诊 ⛔ 不碰;交接后 head 再动 ⇒ 新交接行或本席自审。 - ⛔ 无 check、workflow、队列守卫或巡查脚本读它;入队只认同形记录,标记有无不改判。 diff --git a/.claude/skills/pm-dispatch/references/triage-duties.md b/.claude/skills/pm-dispatch/references/triage-duties.md index 94df158fb81..7691ae7e354 100644 --- a/.claude/skills/pm-dispatch/references/triage-duties.md +++ b/.claude/skills/pm-dispatch/references/triage-duties.md @@ -9,6 +9,12 @@ - 查重缓存住席内:新会话全量拉,其后 `since` 增量;⛔ 不建分支、不共享、不依赖备份。 - 每日一 fire 跑两仓全量对账并归集日频职责;选层按 fire 时刻 ⛔ 不用计数器,简报写明层。 - 每条枚举比对返回数与 `totalCount`,不等 ⇒ 报 `sweep INCOMPLETE` 点名缺口,⛔ 永不报干净。 +- 复审交接:每轮列最新交接行点名现 head 的 open PR,隔离子代理达档跑同形记录、署本席。 +- 本席也被配额拒 ⇒ PR 写一次、留标,⛔ 永不降档审;交接行读法 `record-recognisers.mjs`。 +- 每轮比对自审记录 `Head-sha` 与现 head,越过即过期,纯重生成/只动散文面例外(判已提交树)。 +- 自审 FAIL 过期 ⇒ 同轮达档重审新 head,逐条复查 must-fix,delta commit 当改动审。 +- 自审 PASS 过期 ⇒ PR 记一条 PASS 不再管辖、欠 delta 复审,归本席或新交接行。 +- 轮次记录逐张自审 PR 写 `记录 head → 现 head → 状态`(现行/过期已重审/过期已记)。 - Backlog sweep 是常设职责,每 fire 扫任一析取命中的卡。 - 析取 ①:全裸(无 `pm:*`、无 `needs-user-decision`、无 `domain:*`)。 - 析取 ②:有 `pm:queue` 无 `domain:*`(仅多车道仓);析取 ③:有 `domain:*` 无 pm-state。 @@ -21,7 +27,6 @@ - 排序:队列每轮清空时最新优先;清不空的那一刻起改最老优先。 - 裸卡数 >15 ⇒ 下一 fire 整轮改域分批集中模式,每批 ≤5 张同族卡,照样跑到清空。 - 紧急卡直接分诊:维护者点名或 p0 嫌疑 ⇒ 立即起默认判断档分诊子代理,不等定时轮。 -- 紧急分诊的授权面 = 分诊本身,⛔ 不写码不认领;产出落卡,与定时轮分诊同格式同效力。 - main-red 锚卡由席位先立先派,首触事后补作记录级:可改域,⛔ 不改动作,在飞照补。 - 分类动作每张三选一,外加一个修复通道;裁定写方向、给六态之一。 - 方向在 ADR/本卡裁决/不可重裁规则:贴 `check-prior-rulings.mjs` 的 `Prior rulings read:` 行,或不点。 @@ -33,7 +38,6 @@ - 碰迁移形状或删已发布能力也进决策箱;说明书脱节不进:有裁定出处才是 (b),否则改文档。 - 决策卡速读居四棱块之上、同题,用业务语言先讲事情与选项,末句只问一字:A/B/C 或是否。 - 首行写立卡门类别 ①–④;四类定义、⛔ 清单、四答、理由判据与配额见 `filing-gate.md`。 -- 首触先按业务理由三出口分流,再定级路由;批量卡审计评论带 `Batch-of:` 行。 - `finding` = 三类内待定级:(a) 可复现缺陷(复现或失败探针);(b) 违背已声明契约(引契约文); - (c) AI 写元数据会被运行时拒收或静默丢弃的陷阱;其余进 PR `## Acceptance notes`,⛔ 不立卡。 - (a) 的分界是不完整 vs 错误,不是文档 vs 代码:示例照抄即失败是 (a),漏列成员不是。 @@ -48,10 +52,8 @@ - 判据:违背已声明契约 ⇒ `Bug`,扩大接受集/公开面越出已声明 ⇒ `Feature`,其余 ⇒ `Task`。 - 定级按北极星「优先级」1–3 条;首行 `Path: <定义项> | <清单项 id/缺项> | P<路步> | none`。 - 定义项取北极星「做出来的是什么」或仪器卡的车队决定;无则关;`none` 非分诊缺口。 -- 清单项三态定级(会 fail / 步骤够不到 / 无项断言)与定级判据见 `references/filing-gate.md`。 - 「无则关」= 首触即关 not_planned,带理由与入队三门,⛔ 不定 p3、不 hold;下行同此。 - 所入车道队列 P0/P1 开着(= 未派发,在飞不算)时,三门皆无的 p2/p3 `tooling` 卡同样关。 -- 只报告仪器(放宽 tell、半状态巡查)的修复卡首触即关 not_planned,引裁决 208;在途只有删除。 - 路由是分诊的技术判断,⛔ 永不升级哪个仓的问题;父单是协调节点,永不派发。 - 父单已有子结构的:父单队列标签即可,分诊逐个展开路由、补 `Blocked-by:` 排序。 - 跨层功能点(≥2 层)立父单带 `area:*`+`pm:epic`+清单项级,逐层子单按 `Blocked-by:` 排。 @@ -73,8 +75,6 @@ - 在飞活性复查:认领逾一天无自有产出(commit/PR/评论)⇒ 敲门一次,首行键 `Owned-24h re-check:`。 - 敲门后 `RECLAIM_AFTER_HOURS = 12` 小时无答复 ⇒ `label-write.mjs --release` 一笔中继释放,贴不动。 - 释放:`Release:` 评论(出处三件)+ `Resume-from:` 行 + `pm:dispatched`→`pm:queue` + 清 assignee。 -- 车道席可附证据/前提重验,⛔ 不定级,改标限席改标;每张卡欠一次分诊首触,⛔ 不自分诊。 -- 域分批与 sweep 打包晋级五条照用;每批约定与积压告警见 `references/dispatch-runbook.md`。 - `pm:retriage` 每 fire 先答所求、同笔摘标;须维护者答的入箱;既裁砍项与席改标退回执行席。 - retriage 的异议判据认内容(有评论写明所求)⛔ 不认形状(有一条异议评论)。 - 人工地板(恒呈维护者):功能新增;ADR;协议/公开契约变化;破坏性或难回滚动作。 diff --git a/scripts/pm/record-recognisers.mjs b/scripts/pm/record-recognisers.mjs index 462459281f4..0aae8481a2b 100644 --- a/scripts/pm/record-recognisers.mjs +++ b/scripts/pm/record-recognisers.mjs @@ -26,6 +26,7 @@ * reviewScopeHits the at-tier review's scope floor — `reviewFace`'s `hits`, the record's `Scope:` line * recordCarriesDesignJudgment whether a face's record carries item ④, the full review's design judgment * readLocalRuns the `Local-runs:` line, and `localRunsStand` on it — judged when present, absent not re-judged + * contractReviewHandoff whose review a PR's contract review is — the newest `Contract-review-handoff:` line against the head; `readContractReviewHandoff` reads the line * isModelIdentifierToken the token a refusal must never quote back * REVIEW_OF_RECORD_THREADS the ONE thread set, and REVIEW_OF_RECORD_LOCATION its words * unexplainedPathsBetween the pure-regeneration test a carried record re-runs, prose arm included @@ -796,6 +797,103 @@ export function localRunsStand(reading) { return reading?.state === 'missing' || reading?.state === 'read'; } +/** + * The `Contract-review-handoff:` key line -- the ONE way a dispatching seat + * hands its contract review to the triage seat, read with `Reviewed-by:`'s own + * key discipline. + * + * ⭐ The rule it makes machine-findable (the skill's contract-review reference, + * 〈复核归属与资格〉, and the triage duties' round step): the seat that + * dispatched the work runs the review at the contract-review tier. ONLY when + * that tier's call is quota-refused does the seat hand the review over -- it + * never reviews at a lower tier -- and the hand-off is one PR comment carrying + * this line beside the existing `needs:contract-review` label: + * + * Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (HTTP 429, 2026-10-27T13:00Z) · head 1b03a9c3 + * + * Three facts, each required: the TARGET (`triage`, the closed set of one), the + * TIER that was unavailable -- the constant's NAME, exactly as `Served-tier:` + * spells it, ⛔ never a model id -- with its reason and UTC time in the + * parentheses, and the HEAD the hand-off is for, 7 to 40 hex. A line missing + * any of them is started-and-unreadable: a hand-off nobody can date, or one + * that names no head, is the ambiguity this line exists to remove. + * + * ⛔ No gate reads it. The queue guard keeps reading the ONE `## Contract + * review` record; this line decides only WHO renders that record, and the + * triage seat's record is the same shape, `Reviewed-by:` naming the triage + * seat. `contractReviewHandoff` below is the reading a seat or patrol takes. + */ +export const CONTRACT_REVIEW_HANDOFF_KEY = 'Contract-review-handoff'; +const CONTRACT_REVIEW_HANDOFF_LINE = keyLineRegex(CONTRACT_REVIEW_HANDOFF_KEY); +/** The same key as a MARKER over a whole comment body -- `latestMarkedComment`'s convention (multiline, `g`-less). */ +const CONTRACT_REVIEW_HANDOFF_MARKER = new RegExp(CONTRACT_REVIEW_HANDOFF_LINE.source, 'm'); +/** `triage`, a separator (an em dash, a hyphen pair, a hyphen or a colon), then the rest. */ +const HANDOFF_TARGET = /^triage\b[ \t]*(?:—|--|-|:)?[ \t]*(.*)$/i; +/** `(reason, UTC time)` then ` · head SHA` -- the time is the LAST comma-separated item in the parentheses. */ +const HANDOFF_TAIL = /^\(([^()]*?)[ \t]*,[ \t]*([^,()]+)\)[ \t]*·[ \t]*head[ \t]+`?([0-9a-fA-F]{7,40})`?[ \t]*$/; + +/** + * What one comment declares as a hand-off of its contract review. + * + * @returns {{ state: 'missing' } + * | { state: 'unreadable', line: string } + * | { state: 'read', to: 'triage', tier: string, reason: string, at: string, head: string }} + */ +export function readContractReviewHandoff(text) { + for (const line of String(text ?? '').split(/\r?\n/)) { + const m = CONTRACT_REVIEW_HANDOFF_LINE.exec(line); + if (!m) continue; + const unreadable = { state: 'unreadable', line: quoteLine(line) }; + const target = HANDOFF_TARGET.exec(stripValueDecoration(m[1]).replace(/(?:[ \t]|\*\*|`)+$/, '')); + if (!target) return unreadable; + // The tier is read by NAME, through the one token reader `Served-tier:` uses, so a model id + // written here is refused for the same reason it is refused there. + const named = stripValueDecoration(target[1]); + const tier = TIER_TOKEN.exec(named); + if (!tier || tier[1] !== CONTRACT_REVIEW_TIER_NAME) return unreadable; + const rest = stripValueDecoration(named.slice(tier[0].length)); + const tail = /^unavailable\b[ \t]*(.*)$/i.exec(rest); + const parts = tail ? HANDOFF_TAIL.exec(tail[1].trim()) : null; + if (!parts || parts[1].trim() === '') return unreadable; + return { state: 'read', to: 'triage', tier: tier[1], reason: parts[1].trim(), at: parts[2].trim(), head: parts[3] }; + } + return { state: 'missing' }; +} + +/** + * Whose review this pull request's contract review is, read off its comment thread: + * + * absent no hand-off line on any comment -- the dispatching seat's own review; a + * `needs:contract-review` label alone changes nothing here, and triage does not touch it + * triage the NEWEST hand-off line names the current head -- the triage seat renders the record + * stale the newest hand-off line names an earlier head -- the head moved past the hand-off, so + * it needs a fresh line or the seat's own review; triage does not act on it + * unreadable the thread or the head could not be read, or the newest hand-off line cannot be graded + * + * Newest governs, chosen by `latestMarkedComment` -- the one resolution this file's locator uses -- + * and the head is matched by PREFIX, as `contractReviewHeadMatch` matches a record's span, so the + * abbreviated and the full spelling answer alike. + * + * @param {{ id?: number, body?: string, created_at?: string }[]} rows the PR's comment rows + * @param {string} headSha the pull request's current head + */ +export function contractReviewHandoff(rows, headSha) { + const gaps = []; + if (!Array.isArray(rows)) gaps.push("the pull request's comment thread"); + const head = String(headSha ?? '').toLowerCase(); + if (head.length < H51_SHA_MIN_HEX) gaps.push("the pull request's head sha"); + if (gaps.length > 0) return { state: 'unreadable', gaps }; + const newest = latestMarkedComment(rows, CONTRACT_REVIEW_HANDOFF_MARKER); + if (!newest) return { state: 'absent', read: rows.length }; + const row = rows[newest.index]; + const line = readContractReviewHandoff(row?.body); + const stamp = { id: row?.id ?? null, at: row?.created_at ?? null }; + if (line.state !== 'read') return { state: 'unreadable', gaps: [`the newest hand-off line (comment ${stamp.id ?? '?'}) cannot be read: ${line.line ?? 'no line'}`], ...stamp }; + // PREFIX either way, as `regenChainToHead` meets two spellings of one commit: the line may abbreviate the head. + const current = shaMeets(head, line.head.toLowerCase()); + return { state: current ? 'triage' : 'stale', head: line.head, reason: line.reason, handedAt: line.at, ...stamp }; +} + // --------------------------------------------------------------------------- // The record TEMPLATE — the one machine-read artefact with nothing to copy (#18042) // --------------------------------------------------------------------------- @@ -1446,6 +1544,7 @@ const SELF_TEST_BATTERIES = Object.freeze({ '⭐ B′ with C: a PROSE-ONLY head move keeps the record, decided on the COMMITTED trees like a regeneration': 6, '⭐ letter C: the at-tier review of a mixed diff is SCOPED — `hits` plus what they claim, on the `Scope:` line': 18, '⭐ letter B: a declared NARROWING is a face of its own at CONTRACT_REVIEW_TIER — keyed on the `Clause-②:` line, exact': 17, + '⭐ the `Contract-review-handoff:` line — names the current head ⇒ triage\'s review; head moved ⇒ stale; absent ⇒ the seat\'s own': 13, }); // DELETING an entry silences that battery's floor exactly as effectively as @@ -1458,7 +1557,8 @@ const SELF_TEST_BATTERIES = Object.freeze({ // registering reds here instead of leaving the ④ lines unmeasured. The per-surface scenario lines // and the governed-register wording added one pin to each: 27 → 28 and 16 → 17. Hanging ④ on the narrowing // face (ruling record 6442046166, letter A) flipped three pins and added one to each: 28 → 29 and 17 → 18. -const SELF_TEST_BATTERY_FLOOR = 12; +// Raised 12 → 13 with the hand-off battery (the maintainer's exhausted-tier rule): one battery, one row. +const SELF_TEST_BATTERY_FLOOR = 13; // The key an assertion is filed under when no battery is open. It is not a // declared battery, so it reds by the same set difference rather than silently @@ -1820,6 +1920,30 @@ export async function selfTest() { t('the key is ONE regex, built by the one key-line convention — never a second spelling', LOCAL_RUNS_LINE.source === keyLineRegex('Local-runs').source); t('prose naming the key mid-sentence is not the line — the declaration is line-initial', readLocalRuns('the Local-runs: line goes here').state === 'missing'); + // -- the `Contract-review-handoff:` line -------------------------------------- + // + // The maintainer's rule: a seat with a working contract-review tier reviews + // its own dispatches; only an exhausted tier hands the review to triage, and + // triage must be able to TELL that case apart from a label alone. The line is + // the telling; these cases pin the three readings a seat or patrol takes. + battery('⭐ the `Contract-review-handoff:` line — names the current head ⇒ triage\'s review; head moved ⇒ stale; absent ⇒ the seat\'s own'); + const HO_HEAD = '1b03a9c36be249502c1160b1f262f835f7ccaf02'; + const HO_LINE = (head = HO_HEAD, reason = 'HTTP 429', at = '2026-10-27T13:00Z') => `${CONTRACT_REVIEW_HANDOFF_KEY}: triage — ${CONTRACT_REVIEW_TIER_NAME} unavailable (${reason}, ${at}) · head ${head}`; + const HO_ROW = (line, id = 4401, at = '2026-10-27T13:01:00Z') => ({ id, created_at: at, body: `Seat note — the review tier was refused this round.\n\n${line}\n\nLabel kept.` }); + t('⭐ the line names the CURRENT head ⇒ the review is triage\'s, with the reason, the time and the comment that handed it off', (() => { const r = contractReviewHandoff([HO_ROW(HO_LINE())], HO_HEAD); return r.state === 'triage' && r.head === HO_HEAD && r.reason === 'HTTP 429' && r.handedAt === '2026-10-27T13:00Z' && r.id === 4401; })()); + t('⭐ the head MOVED past the line ⇒ stale, naming the head the hand-off was for — a fresh line or the seat\'s own review', (() => { const r = contractReviewHandoff([HO_ROW(HO_LINE())], 'c260fddc'.padEnd(40, '0')); return r.state === 'stale' && r.head === HO_HEAD; })()); + t('⭐ NO hand-off line on any comment ⇒ absent, the seat\'s own review — a record, a seat note, a label mention change nothing', (() => { const r = contractReviewHandoff([RECORD_ON_9AF9, { id: 4402, created_at: '2026-10-27T13:02:00Z', body: 'ACCEPT — `needs:contract-review` stays until the seat reviews.' }], HO_HEAD); return r.state === 'absent' && r.read === 2; })()); + t('the head is matched by PREFIX, as a record\'s span is: an abbreviated head on the line names the full head, and the reverse', contractReviewHandoff([HO_ROW(HO_LINE(HO_HEAD.slice(0, 7)))], HO_HEAD).state === 'triage' && contractReviewHandoff([HO_ROW(HO_LINE(HO_HEAD))], HO_HEAD.slice(0, 8)).state === 'triage'); + t('NEWEST governs — an older line on an old head under a newer one on the current head reads triage\'s, and the reverse reads stale', contractReviewHandoff([HO_ROW(HO_LINE('deadbeef1'), 4403, '2026-10-27T12:00:00Z'), HO_ROW(HO_LINE(), 4404, '2026-10-27T13:30:00Z')], HO_HEAD).state === 'triage' && contractReviewHandoff([HO_ROW(HO_LINE(), 4403, '2026-10-27T12:00:00Z'), HO_ROW(HO_LINE('deadbeef1'), 4404, '2026-10-27T13:30:00Z')], HO_HEAD).state === 'stale'); + t('decoration reads: a bulleted bolded key, a backticked tier name, a backticked head, a blockquoted line', (() => { const dec = `> - **${CONTRACT_REVIEW_HANDOFF_KEY}:** triage — \`${CONTRACT_REVIEW_TIER_NAME}\` unavailable (quota exhausted, 2026-10-27T13:00Z) · head \`${HO_HEAD.slice(0, 12)}\``; const r = readContractReviewHandoff(dec); return r.state === 'read' && r.head === HO_HEAD.slice(0, 12) && r.reason === 'quota exhausted' && contractReviewHandoff([HO_ROW(dec)], HO_HEAD).state === 'triage'; })()); + t('the separator is any of the four spellings, and the reason may itself carry a comma — the time is the LAST item in the parentheses', ['—', '--', '-', ':'].every((sep) => readContractReviewHandoff(`${CONTRACT_REVIEW_HANDOFF_KEY}: triage ${sep} ${CONTRACT_REVIEW_TIER_NAME} unavailable (HTTP 429, quota exhausted, 2026-10-27T13:00Z) · head ${HO_HEAD}`).reason === 'HTTP 429, quota exhausted')); + t('⛔ a line with no reason, no time or no head is started-and-unreadable, never a reading — the ambiguity the line exists to remove', [`${CONTRACT_REVIEW_HANDOFF_KEY}: triage — ${CONTRACT_REVIEW_TIER_NAME} unavailable (, 2026-10-27T13:00Z) · head ${HO_HEAD}`, `${CONTRACT_REVIEW_HANDOFF_KEY}: triage — ${CONTRACT_REVIEW_TIER_NAME} unavailable (HTTP 429) · head ${HO_HEAD}`, `${CONTRACT_REVIEW_HANDOFF_KEY}: triage — ${CONTRACT_REVIEW_TIER_NAME} unavailable (HTTP 429, 2026-10-27T13:00Z)`, `${CONTRACT_REVIEW_HANDOFF_KEY}: triage — ${CONTRACT_REVIEW_TIER_NAME} unavailable (HTTP 429, 2026-10-27T13:00Z) · head 1b03a`, `${CONTRACT_REVIEW_HANDOFF_KEY}:`].every((l) => readContractReviewHandoff(l).state === 'unreadable')); + t('⛔ the target is the closed set of one and the tier is the constant\'s NAME — another seat, the default tier or a model id is unreadable', [`${CONTRACT_REVIEW_HANDOFF_KEY}: director — ${CONTRACT_REVIEW_TIER_NAME} unavailable (HTTP 429, 2026-10-27T13:00Z) · head ${HO_HEAD}`, `${CONTRACT_REVIEW_HANDOFF_KEY}: triage — ${TIER_DEFAULT_NAME} unavailable (HTTP 429, 2026-10-27T13:00Z) · head ${HO_HEAD}`, `${CONTRACT_REVIEW_HANDOFF_KEY}: triage — ${CONTRACT_REVIEW_TIER} unavailable (HTTP 429, 2026-10-27T13:00Z) · head ${HO_HEAD}`].every((l) => readContractReviewHandoff(l).state === 'unreadable')); + t('an unreadable NEWEST line makes the thread unreadable, naming the comment — never absent, never stale', (() => { const r = contractReviewHandoff([HO_ROW(`${CONTRACT_REVIEW_HANDOFF_KEY}: triage — ${CONTRACT_REVIEW_TIER_NAME} unavailable (HTTP 429) · head ${HO_HEAD}`, 4405)], HO_HEAD); return r.state === 'unreadable' && r.gaps.length === 1 && r.gaps[0].includes('4405'); })()); + t('a thread that is not an array, or a head too short to match, is a read that could not be made', contractReviewHandoff(null, HO_HEAD).state === 'unreadable' && contractReviewHandoff([], 'abc').state === 'unreadable' && contractReviewHandoff([], HO_HEAD).state === 'absent'); + t('the key is ONE regex, built by the one key-line convention, and prose naming it mid-sentence is not the line', CONTRACT_REVIEW_HANDOFF_LINE.source === keyLineRegex(CONTRACT_REVIEW_HANDOFF_KEY).source && readContractReviewHandoff(`the ${CONTRACT_REVIEW_HANDOFF_KEY}: line goes on the PR`).state === 'missing' && contractReviewHandoff([HO_ROW(`the ${CONTRACT_REVIEW_HANDOFF_KEY}: line goes on the PR`)], HO_HEAD).state === 'absent'); + t('⛔ no gate reads it: the queue guard\'s record reading is untouched — a hand-off line beside a record on this head still reads FOUND', (() => { const r = locateReviewOfRecord(pairOf({ prComments: [RECORD_ON_9AF9, HO_ROW(HO_LINE(HEAD_9AF9))] })); return r.state === 'found' && r.id === 3301; })()); + // -- #18042: the copyable record TEMPLATE ---------------------------------- // // `references/contract-review.md` DESCRIBES the record in prose and once