1676 lines
106 KiB
JavaScript
1676 lines
106 KiB
JavaScript
// 汉·公卿年表 —— 「我在某朝为官,身边站着谁」。
|
||
//
|
||
// 定位:与 dynasties.js / decisions.js / talents.js 同级的【纯常量表 + 纯函数】。无 IO、无 DB、无 LLM。
|
||
//
|
||
// 四刀的位置:
|
||
// 第一刀 dynasties.js —— 我在每朝每代的【位置】(性格 × 制度 → 位阶)
|
||
// 第二刀 dynasties.js —— 那个位置的【天花板】(通道即杠杆)
|
||
// 第三刀 decisions.js —— 那个位置上的【选择】,与它能传多远
|
||
// 第四刀 本文件 —— 你站在那个位置上的【那一年】,身边站着谁
|
||
//
|
||
// ⚠ courtAt / fateOf 必须是确定性纯函数,绝不调 LLM。理由与 dynasties.js / decisions.js 同:
|
||
// 「景帝三年的御史大夫是晁错」是史料里的硬事实,不是可以现编的东西。让 LLM 编一份同僚名单,
|
||
// 用户查一次《汉书》就发现是假的 —— 而这个功能的用户,正是会去查《汉书》的那批人。
|
||
//
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
// 【这张表凭什么值钱】
|
||
//
|
||
// 《汉书·百官公卿表》分上下两卷,是两样完全不同的东西:
|
||
// · 上卷 = 官制【说明书】:某官秦置,掌某事,秩若干石,属官若干。—— 那是 dynasties.js 的料。
|
||
// · 下卷 = 公卿【年表】:按帝王纪年逐年记,哪一年谁拜了丞相、谁免了、谁薨了、谁腰斩了。
|
||
//
|
||
// ★ 下卷比上卷值钱,因为【皇帝是天然的时间轴】。给定「景帝三年,君迁中大夫」,
|
||
// 下卷能告诉你那一年:丞相是陶青、太尉是周亚夫(刚拜)、御史大夫是晁错。
|
||
// ——而景帝三年正月壬子,晁错要斩。那年七国反。而你在场。
|
||
//
|
||
// ★★【同僚图谱不是装饰,它是决策点的生成器】:
|
||
// 你在哪一年、在哪个位置、身边站着谁 —— 这三样一齐,关口自己就有了。
|
||
// decisions.js 的关口是【手写】的(南齐四户两道题);本文件是想让关口【长出来】的那一半。
|
||
// ⚠ 但本文件【不生成关口】,它只提供事实。生成是别人的事,别在这儿加。
|
||
//
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
// 史学口径 —— 本文件的史料经 2026-07-16 一轮考实:
|
||
// · curl -sk 取生 HTML 逐字比对,【未用 WebFetch】。
|
||
// · 两个独立见证:汉川草庐 www.sidneyluo.net/a/a02/019b.htm(繁体)与 ctext.org
|
||
// han-shu/bai-guan-gong-qing-biao-xia。两边各自解析成 218 行的表格,行数、纪年逐行相符。
|
||
// · 景帝元年—武帝後元二年(rows 56–125)区间内【逐格】比对:291 格,异文 24 处。分账:
|
||
// - 14 处「衞/衛」同字异形(无关文义)
|
||
// - 2 处 ctext 的 OCR 坏字(「平【觉】侯」「風發【鲷】」,见 WITNESS_NOTE.ctextFlaws)
|
||
// - 3 处「歐/敺」同音异写(顏師古卷内注「歐讀與驅同」、卷四十九注「音區」,可证同音)
|
||
// - 5 处【真要紧的】。其中 3 处落在本表已收的条目里,已逐条记进 caveat,
|
||
// 【一处都没有替读者选】:晁错之名(朝/晁)、直不疑之终(死/免)、霍光之月(三/二)。
|
||
// 另 2 处落在本表【未收】的格 —— 元狩六年右内史「正鼂/王晁」(人名两字全异,
|
||
// 且不在覆盖范围)、景帝中二年中尉「一格只有官名无人」(整格是阙文,按 SHIGU_NOTE 丢弃)。
|
||
// ⚠ 照实说:那两处不是「解决了」,是【没收它们】。
|
||
//
|
||
// 【已删除的错误说法,不许复活】
|
||
//
|
||
// · ✗「表里说晁错腰斩于东市」→ 错。本表(卷十九下)在景帝三年御史大夫栏下只有【九个字】:
|
||
// 「正月壬子,錯有罪要斬」。「东市」二字【不在这一卷】,出《汉书》卷四十九《爰盎晁錯傳》
|
||
// (「錯衣朝衣斬東巿」)。这是【两卷】。带卷次的错误比没出处的错误危害大十倍 ——
|
||
// 把传里的细节记到表的账上,正是这种错误。
|
||
// ⚠ 又:本表作「要斬」不作「腰斬」(要,通腰)。照录原字,不许径改。
|
||
//
|
||
// · ✗「「N年遷」可以加到拜官那年算出去职之年」→ 错,已【实测自相矛盾】,不许复活:
|
||
// - 周亚夫:景帝三年(前154)拜太尉,表注「五年遷」;实际迁丞相在景帝七年(前150)。
|
||
// 前154 算第 1 年 → 前150 是第 5 年。【含拜年】才对得上。
|
||
// - 陶青:孝文後元二年(前162)拜御史大夫,表注「七年遷」;实际迁丞相在孝景二年(前155)。
|
||
// 前162 + 7 = 前155。【不含拜年】才对得上。
|
||
// - 刘舍:景帝七年(前150)拜御史大夫,表注「三年遷」;实际迁丞相在中元三年(前147)。
|
||
// 含拜年是第 4 年,不含拜年是 +3 = 前147 —— 两种读法在这里【又反过来】。
|
||
// 三个样本,两种读法互斥,没有一种读法通吃。→ 本表【绝不计算】去职之年:
|
||
// 「N年」只照录进 quote,任期终点一律取【后任的拜官记录】(那是有日子的硬记载)。
|
||
// ⚠ 顏師古在本卷卷首的注里【自己就提示过】这一类记法有问题(见 SHIGU_NOTE),
|
||
// 虽然他说的是另一个毛病,但方向一致:这张表的「若干年」不是可算的字段。
|
||
//
|
||
// · ✗「景帝前元三年」→ 表原文【没有「前元」】。本表纪年栏原文只作「孝景元年、二、三……七」,
|
||
// 然后「中元年、二……六」,然后「後元年、二、三」。只有「中」「後」两个年号,
|
||
// 头一段【无号】。「前元」是后人为了跟「中/後」对称造出来的叫法。晁错死在【孝景三年】。
|
||
//
|
||
// · ✗「汉的纪年跟公历一一对应」→ 错,见 CALENDAR_NOTE。太初改历之前,一个汉年跨两个公历年。
|
||
//
|
||
// · ✗「表里的列将军栏可以当那一年的将军名单」→ 错,本表【自己就阙】:元狩四年栏内写
|
||
// 「大將軍衞青為大司馬大將軍」,可是【卫青拜大将军这一笔,表中根本没有】。
|
||
// 一个「大将军」凭空出现在他升迁的那一格里。→ 列将军栏是【散记】,不是名单。见 COVERAGE。
|
||
//
|
||
// · ✗「表里同名就是同一个人」→ 错,本表元光四年【同一年】有两个「張敺」:
|
||
// 「中尉張敺為御史大夫」与「宣平侯張敺為太常」——一个是中尉迁御史大夫,一个是宣平侯拜太常,
|
||
// 封邑都不同。→ 除非本表自己的记事链能把人串起来(见 PERSON_NOTE),否则【不许并人】。
|
||
//
|
||
// 【必须带限定语的说法】
|
||
// · 本表把「太尉」和「大司馬」排在【同一栏】。但「大司马是不是太尉的后身」是制度史上的问题
|
||
// (武帝的大司马是加在大将军/票骑将军头上的加官,不是独立的一府),【本文件不表态】——
|
||
// 它只照录「表把它们排在同一栏」这个事实。要论制度,那是 dynasties.js 的地界,且得先有史料。
|
||
// · 武帝诸年号(建元、元光……)是否【自始行用】、抑或后来追建,学界有争论。
|
||
// 本文件照《汉书》的纪年书写,【不表态】—— 那超出这张表能证的范围。
|
||
// · 公历年是【换算】,原表只有纪年。换算与 ctext 该表自带的「公元前」栏逐行相符
|
||
// (前206 起连续递减到前87,无跳档),但那一栏也是【今人加的】,不是班固的字。
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
|
||
// ── 出处:全表共用一个 source ──
|
||
export const BIAO = '《汉书》卷十九下·百官公卿表第七下';
|
||
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
// ★★★ TABLE_SCOPE —— 【这张表说的是哪个汉】
|
||
//
|
||
// 2026-07-17 第五刀加。加它的理由,是本刀查出来的头号事实,而且它推翻了这一刀的前提:
|
||
//
|
||
// 【本表 = 西汉】景帝元年(前156)— 武帝後元二年(前87)。
|
||
// 【dynasties.js 的 'han' = 东汉】era:'东汉' span:'25–220'。
|
||
// ⇒ 两段【不重叠一年】。本产品的七朝里【没有一朝】装得下这张表。
|
||
//
|
||
// ★ 这不是「数据少了一点」,这是【叫「汉」的不是同一个汉】——
|
||
// 而它正是 dynasties.js 自己的头号铁律禁的那一件事(时代错置)。证据是本表自己的官名:
|
||
// 本表通篇的「御史大夫」,在引擎那个汉里【根本不存在】——《续汉书·百官志一》刘昭注引
|
||
// 《汉官仪》:「綏和元年,罷御史大夫官」,绥和元年 = 前 8 年,比东汉开国早三十余年。
|
||
// (dynasties.js bizhao.ceiling 那一段逐字写过这件事,是本表最贵的那种错的样本。)
|
||
// ⇒ 把 courtAt(-154) 接到 dynastyId='han' 上,就是把晁错、周亚夫塞进一部【东汉】的传里 ——
|
||
// 那本书的位阶是按东汉的察举/辟召算的,而它身边站着一群西汉人。
|
||
// ★★ kaoyan.js 早就把这件事写成了断言(renwu.js XIHAN_ONLY),只是【没人把它接到这张表上】。
|
||
//
|
||
// 【所以本表怎么办】—— 一句话:本表【不认领】任何一朝,而这是【数据】不是注释:
|
||
// dynastyIds: [] ⇒ services/court.js 查不到任何一朝 ⇒ 一律照实答「本表没有这一朝的年表」。
|
||
// ⚠ 这【不是】「那一年没人」。两回事,见 courtAt 的 status:'不載'。
|
||
//
|
||
// ★ 哪天有人真把西汉加进 dynasties.js:把它的 id 填进 dynastyIds 即可,
|
||
// 而 assertGongqingInvariants() 会【逐个核对它的 span 真的盖得住本表的年份】——
|
||
// 填错了当场报错。⇒ 认领是【要被验的】,不是写上就算。
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
export const TABLE_SCOPE = Object.freeze({
|
||
era: '西汉',
|
||
what: '《汉书》卷十九下·百官公卿表第七下 —— 汉景帝元年(前156)至汉武帝後元二年(前87)',
|
||
years: { from: -156, to: -87 },
|
||
// ★★ 本表认领的朝代 id(dynasties.js 的 DYNASTIES[].id)。【故意是空的】。
|
||
dynastyIds: [],
|
||
emptyWhy:
|
||
'★★【本产品的七朝里没有一朝装得下这张表】:本表是【西汉】(前156–前87),' +
|
||
'而 dynasties.js 的「汉」是【东汉】(span 25–220)—— 两段不重叠一年。' +
|
||
'⚠ 故这里是空的【不是漏填】,是结论:本表【不认领】任何一朝。' +
|
||
'★ 证据是本表自己的官名:通篇的「御史大夫」在东汉【不存在】(绥和元年/前8 罢,' +
|
||
'《续汉书·百官志一》刘昭注引《汉官仪》;dynasties.js 自己逐字写过)。' +
|
||
'⇒ 把本表接到 han 上 = 把晁错塞进一部东汉的传里 = 时代错置。' +
|
||
'这正是 kaoyan.js 对 renwu.js 那十个人已经断言过的同一件事,' +
|
||
'只是此前【没有人把那条断言接到这张表上】。',
|
||
note:
|
||
'★ 要让本表接得上,需要的【不是代码,是老板拍板】:往 dynasties.js 加一朝【西汉】。' +
|
||
'⚠ 而那不是本刀能替他做的决定 —— 加一朝要有梯子(秩石)、通道、天花板与原文,' +
|
||
'是第一刀那个量级的活。⇒ 本刀照实报,不替他假装接上了。',
|
||
});
|
||
|
||
// 见证与异文的总说明。⚠ 前端展示引文时必须能拿到它。
|
||
export const WITNESS_NOTE = Object.freeze({
|
||
witnesses: [
|
||
'汉川草庐 www.sidneyluo.net/a/a02/019b.htm(繁体 UTF-8,证书自签,取生 HTML)',
|
||
'ctext.org han-shu/bai-guan-gong-qing-biao-xia(取生 HTML)',
|
||
],
|
||
method:
|
||
'两边各自解析成 218 行表格,纪年逐行相符;景帝元年—武帝後元二年区间 291 格逐格比对,' +
|
||
'异文 24 处 = 14 同字异形(衞/衛)+ 2 ctext 坏字 + 3 同音异写(歐/敺)+ 5 要紧的。' +
|
||
'★ 落在已收条目里的异文一律记进 caveat,不替读者选;' +
|
||
'⚠ 另有 2 处要紧异文落在【未收的格】(元狩六年右内史、景帝中二年中尉),' +
|
||
'那不是「解决了」,是【没收它们】—— 照实说。',
|
||
ctextFlaws:
|
||
'⚠ ctext 该表有 OCR 坏字,且【自带指纹】——坏字是简体,混在繁体正文里一眼可辨:' +
|
||
'「平棘侯薛澤」讹作「平觉侯」、「孝文廟風發瓦」讹作「風發鲷」。凡遇 ctext 单独出简体字,' +
|
||
'一律判为 ctext 之误,从草庐。这不是偏袒草庐,是这两处有【内证】。',
|
||
punctuation:
|
||
'★ 引文【用字】照两个见证逐字比对;【标点为本项目自断】,未采用任何现代点校本的标点、' +
|
||
'分段或校勘成果。⚠ 这一条不是客套:两个见证的标点【完全一致】,正说明它们同出一个现代' +
|
||
'点校祖本(很可能是中华书局本)—— 原文字符属公有领域(班固,东汉),标点却是现代点校者的' +
|
||
'智力成果,受著作权保护。见证一致恰恰是【不能照抄】的理由,不是可以照抄的理由。',
|
||
});
|
||
|
||
// 顏師古在本卷【卷首】的注。★ 这条注是本文件三个数据结构决定的依据,故必须留着。
|
||
// ⚠ 它是【注】不是正文 —— 顏師古是唐人,班固是东汉人。凡「師古曰/應劭曰/如淳曰」开头的
|
||
// 一律是后人注,本文件的 quote 字段里【一个字都不许有】(解析时已按 /師古曰:「…」/ 剥除)。
|
||
// ⚠ 单证:只见于草庐本,ctext 的该表不载注。照实说,不装作有两个见证。
|
||
export const SHIGU_NOTE = Object.freeze({
|
||
what: '顏師古卷首注:这张表自己承认哪些地方是阙文',
|
||
source: '《汉书》卷十九下·百官公卿表第七下 卷首 顏師古注',
|
||
quote:
|
||
'此表中記公卿姓名不具,及但舉其官而無名,或言若干年不載遷免死者,皆史之闕文,不可得知。',
|
||
caveat:
|
||
'⚠【是注不是正文】:顏師古,唐人。⚠【单证】:草庐本有,ctext 该表不载注,未取得第二见证。' +
|
||
'⚠ 标点为本项目自断。',
|
||
why:
|
||
'★ 本文件三处设计直接依据这条注:' +
|
||
'(1)「記公卿姓名不具」→ 表里大量只有一个字的人名(「奉常斿」「廷尉勝」),' +
|
||
'person 一律置 null,【不许替它猜姓】;' +
|
||
'(2)「但舉其官而無名」→ 表里真有只写官名不写人的格(中元二年中尉栏只有「中尉」二字),' +
|
||
'这种格【整格丢弃】,不入库;' +
|
||
'(3)「或言若干年不載遷免死者」→ 「若干年」这种记法连顏師古都点了名,' +
|
||
'本表故【不计算】去职之年(另见上文「不许复活」第二条:实测三个样本,两种读法互斥)。',
|
||
});
|
||
|
||
// ── 纪年 → 公历:这一段是整个模块最容易出错、也最容易被人抓住的地方 ──
|
||
export const CALENDAR_NOTE = Object.freeze({
|
||
yearSign:
|
||
'★ year 是【公元前的年数取负】:-154 读作「公元前 154 年」。' +
|
||
'⚠ 这【不是】天文学年号 —— 天文学年号有公元 0 年,公元前 154 年在那套里记作 -153。' +
|
||
'两套差一。本表一律用前者(史学惯例)。不许混。',
|
||
suiShou:
|
||
'★★ 汉初承秦制,【以十月为岁首】。武帝太初元年才改:《汉书·武帝纪》太初元年正文' +
|
||
'「夏五月,正歷,以正月為歲首」(这是班固正文;紧跟其后的「師古曰」是注,不算)。' +
|
||
'→ 太初改历【之前】,一个汉年跨两个公历年:十月、十一月、十二月在前一个公历年,' +
|
||
'正月到九月在后一个。' +
|
||
'本表 year 取【该汉年正月所在的公历年】(与 ctext 该表的「公元前」栏一致)。' +
|
||
'⚠ 因此:太初元年(前104)之前,凡 month 是十月/十一月/十二月的条目,' +
|
||
'其【实际公历年应减一】—— 用 gregorianYearOf() 拿,不要直接读 year。' +
|
||
'实例:建元二年「十月丞相嬰免」,year 是 -139,可窦婴免相那个十月实际在公元前 140 年。',
|
||
taichuYear: -104,
|
||
eraNames:
|
||
'⚠ 表原文【没有「前元」】:景帝纪年原文只作「孝景元年、二、三……七」「中元年……」' +
|
||
'「後元年……」。只有「中」「後」两个号,头一段无号。「景帝前元三年」是后人的叫法。',
|
||
reignEras:
|
||
'⚠ 武帝诸年号是否自始行用抑或后来追建,学界有争论。本文件照《汉书》的纪年书写,不表态。',
|
||
});
|
||
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
// RULERS —— 帝王 + 纪年 → 公历。★ 这正是我们缺的那张纪年表。
|
||
//
|
||
// era.raw 表的纪年原文写法(表只在改元那年写全,其余年只写数字,本表补全并标明是【补的】)
|
||
// from/to 公历(负数 = 公元前)
|
||
// count 这一段几年 —— ⚠ 不是我数的,是【表自己的行数】:解析出的 218 行里,
|
||
// 改元行到下一个改元行之间正好有这么多行,且与 ctext 的「公元前」栏连续递减相符。
|
||
// 两个见证 + 行数 + 公历连续性,三重交叉。
|
||
// seedOnly ★ true = 这个帝王的公卿数据【不在本表覆盖范围内】,列他只为让 courtAt 接得上:
|
||
// 景帝元年的丞相是文帝朝拜的,不把文帝那两笔放进来,courtAt(-156) 就是空的。
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
export const RULERS = [
|
||
{
|
||
id: 'wen',
|
||
name: '汉文帝',
|
||
tableName: '孝文',
|
||
seedOnly: true,
|
||
seedNote: '★ 文帝朝【不在覆盖范围】。列他只为接住景帝元年在任的丞相与御史大夫。',
|
||
eras: [
|
||
{ key: '孝文', raw: '孝文元年', name: null, from: -179, to: -164, count: 16 },
|
||
{ key: '孝文後', raw: '後元年', name: '後', from: -163, to: -157, count: 7 },
|
||
],
|
||
},
|
||
{
|
||
id: 'jing',
|
||
name: '汉景帝',
|
||
tableName: '孝景',
|
||
eras: [
|
||
{
|
||
key: '孝景',
|
||
raw: '孝景元年',
|
||
name: null,
|
||
nameNote: '⚠ 无年号。表原文只作「孝景元年、二、三……七」。「前元」是后人的叫法,不许复活。',
|
||
from: -156,
|
||
to: -150,
|
||
count: 7,
|
||
},
|
||
{ key: '孝景中', raw: '中元年', name: '中', from: -149, to: -144, count: 6 },
|
||
{ key: '孝景後', raw: '後元年', name: '後', from: -143, to: -141, count: 3 },
|
||
],
|
||
},
|
||
{
|
||
id: 'wu',
|
||
name: '汉武帝',
|
||
tableName: '孝武',
|
||
eras: [
|
||
{ key: '建元', raw: '孝武建元元年', name: '建元', from: -140, to: -135, count: 6 },
|
||
{ key: '元光', raw: '元光元年', name: '元光', from: -134, to: -129, count: 6 },
|
||
{ key: '元朔', raw: '元朔元年', name: '元朔', from: -128, to: -123, count: 6 },
|
||
{ key: '元狩', raw: '元狩元年', name: '元狩', from: -122, to: -117, count: 6 },
|
||
{ key: '元鼎', raw: '元鼎元年', name: '元鼎', from: -116, to: -111, count: 6 },
|
||
{ key: '元封', raw: '元封元年', name: '元封', from: -110, to: -105, count: 6 },
|
||
{ key: '太初', raw: '太初元年', name: '太初', from: -104, to: -101, count: 4 },
|
||
{ key: '天漢', raw: '天漢元年', name: '天漢', from: -100, to: -97, count: 4 },
|
||
{ key: '太始', raw: '太始元年', name: '太始', from: -96, to: -93, count: 4 },
|
||
{ key: '征和', raw: '征和元年', name: '征和', from: -92, to: -89, count: 4 },
|
||
{ key: '後元', raw: '後元元年', name: '後元', from: -88, to: -87, count: 2 },
|
||
],
|
||
},
|
||
];
|
||
|
||
const ALL_ERAS = RULERS.flatMap((r) => r.eras.map((e) => ({ ...e, rulerId: r.id, rulerName: r.name, seedOnly: !!r.seedOnly })));
|
||
|
||
// ── 覆盖范围。★ 必须能被程序读到,不能只写在注释里 ──
|
||
// 【为什么要有这个】:这张表是【逐格抠出来的】,不是全抠完的。
|
||
// 一个只有三公的库,如果 courtAt 返回时不说「九卿我没抠全」,前端就会拿它当全名单画图,
|
||
// 然后有人发现元狩三年的九卿只有一个 —— 那不是数据少,那是【说了谎】。
|
||
export const COVERAGE = Object.freeze({
|
||
years: { from: -156, to: -87 },
|
||
yearsNote: '孝景元年(前156)— 孝武後元二年(前87)。景帝、武帝两朝,七十年。',
|
||
sangong: {
|
||
complete: true,
|
||
offices: ['丞相', '相國', '左丞相', '右丞相', '太尉', '大司馬', '御史大夫'],
|
||
note:
|
||
'★【全覆盖】:本表丞相栏、太尉/大司马栏、御史大夫栏在前156—前87 之间的每一格都已录入,' +
|
||
'一格没落。故 courtAt 的三公是可信的。',
|
||
},
|
||
jiangjun: {
|
||
complete: false,
|
||
note:
|
||
'⚠【表自己就阙】:列将军栏是散记不是名单 —— 元狩四年写「大將軍衞青為大司馬大將軍」,' +
|
||
'而卫青【拜大将军那一笔表中根本没有】。已录入的照录,但【不许当作那一年的将军名单】。',
|
||
},
|
||
jiuqing: {
|
||
complete: false,
|
||
note:
|
||
'⚠【只抠了两处,其余没抠】:(1) 孝景三年(前154)那一年的九卿全格 —— 因为那是样板年;' +
|
||
'(2) 主角们的起家一步(晁错、公孙弘、张汤)。其余年份的九卿栏【没抠】,不是没有。' +
|
||
'★ courtAt 的 others 字段【绝不许】当作那一年的九卿全名单。',
|
||
},
|
||
seeds: {
|
||
note:
|
||
'文帝朝录入 4 笔【接续用】的记事(灌婴、申屠嘉、陶青),只为让 courtAt(-156) 接得上。' +
|
||
'文帝朝【不在覆盖范围】,不许拿 courtAt(-160) 当数。',
|
||
},
|
||
});
|
||
|
||
// ── 座次:本表按【原表的栏】分,不按制度分 ──
|
||
// ⚠ 为什么不叫「三公」而叫「栏」:把太尉和大司马归一栏是【原表的编排】,
|
||
// 不是本项目对「大司马是不是太尉后身」的判断。本文件不表态,见卷首「必须带限定语的说法」。
|
||
export const SEATS = [
|
||
{ id: 'chengxiang', name: '丞相之位', column: 1, offices: ['相國', '丞相', '左丞相', '右丞相'] },
|
||
{
|
||
id: 'taiwei',
|
||
name: '太尉/大司马之位',
|
||
column: 2,
|
||
offices: ['太尉', '大司馬大將軍', '大司馬票騎將軍'],
|
||
note: '⚠ 表把太尉与大司马排在同一栏。这是原表的编排,不是本文件对二者关系的判断。',
|
||
},
|
||
{ id: 'yushi', name: '御史大夫之位', column: 3, offices: ['御史大夫'] },
|
||
{
|
||
id: 'jiangjun',
|
||
name: '列将军',
|
||
column: 4,
|
||
offices: ['大將軍', '票騎將軍', '車騎將軍', '衞將軍', '左將軍'],
|
||
note: '⚠ 散记,非名单。见 COVERAGE.jiangjun。',
|
||
},
|
||
];
|
||
const SEAT_BY_OFFICE = {};
|
||
for (const s of SEATS) for (const o of s.offices) SEAT_BY_OFFICE[o] = s.id;
|
||
|
||
// ── 事件词:一律用【表自己的字】,不许翻译成「离职」「任命」这种现代词 ──
|
||
// ⚠ 为什么这也要较真:「免」「薨」「卒」「死」「自殺」「要斬」「下獄死」「誅」在表里是
|
||
// 分得清清楚楚的七八个词。合并成「离任」,这张表最值钱的东西——【一个人怎么完的】——就没了。
|
||
export const EVENTS = [
|
||
{ id: 'bai', word: '拜', terminal: false, gloss: '就任。表的写法是「某为某官」。' },
|
||
{ id: 'mian', word: '免', terminal: true, gloss: '免职。活着。' },
|
||
{ id: 'qian', word: '遷', terminal: true, gloss: '迁转他官。' },
|
||
{ id: 'hong', word: '薨', terminal: true, gloss: '死在任上。诸侯与贵臣之死曰薨。' },
|
||
{ id: 'zu', word: '卒', terminal: true, gloss: '死在任上。' },
|
||
{ id: 'si', word: '死', terminal: true, gloss: '死。表在这个字上很省,别替它推死因。' },
|
||
{ id: 'zisha', word: '自殺', terminal: true, gloss: '自杀。表多作「有罪自殺」。' },
|
||
{ id: 'yaozhan', word: '要斬', terminal: true, gloss: '腰斩。★ 表作「要斬」,要通腰。照录原字。' },
|
||
{ id: 'xiayusi', word: '下獄死', terminal: true, gloss: '下狱而死。' },
|
||
{ id: 'zhu', word: '誅', terminal: true, gloss: '诛。' },
|
||
{ id: 'guansheng', word: '官省', terminal: true, gloss: '这个官【裁了】。★ 太尉一栏大半个世纪都是这两个字。' },
|
||
];
|
||
const EVENT_WORDS = new Set(EVENTS.map((e) => e.word));
|
||
const TERMINAL_WORDS = new Set(EVENTS.filter((e) => e.terminal).map((e) => e.word));
|
||
|
||
// ── 人名:本表怎么认人 ──
|
||
export const PERSON_NOTE = Object.freeze({
|
||
rule:
|
||
'本表【记事链】的行文惯例:一个人头回出现给全名(「魏其侯竇嬰為丞相」),' +
|
||
'此后同一个位子上再提他就只用名(「十月丞相嬰免」)。' +
|
||
'name 一律照录原文那一格的写法;person 是【本项目按这条链解出来的】规范名。',
|
||
limit:
|
||
'★ 解不出来就置 null,【不许猜】:「奉常殷」「廷尉勝」「御史大夫介」这类只有一个字的,' +
|
||
'正是顏師古说的「記公卿姓名不具……皆史之闕文,不可得知」。null 不是数据缺失,是史料如此。',
|
||
homonym:
|
||
'⚠【同名不并人】:元光四年同一年两个「張敺」(中尉張敺迁御史大夫、宣平侯張敺拜太常),' +
|
||
'封邑不同,显非一人。凡本表记事链串不起来的,一律各是各的,personUncertain 标出来。',
|
||
});
|
||
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
// GONGQING —— 事件流。★ 注意:这张表是【记事链】,不是【年度花名册】。
|
||
//
|
||
// 它只记【变动】:拜、免、薨、要斩。景帝三年那一格里【没有丞相】,
|
||
// 因为丞相陶青是景帝二年八月拜的,那年他没动。
|
||
// → 所以 courtAt(year) 只能【重放】这条链,不能查表。这跟 decisions.js 的 replay() 是同一个道理。
|
||
//
|
||
// 字段:
|
||
// year 公历(负 = 公元前)。⚠ 十月/十一月/十二月的条目见 CALENDAR_NOTE,用 gregorianYearOf()
|
||
// era 纪年(本项目补全的完整写法,如「孝景三年」)
|
||
// eraRaw 纪年【原文】(表在非改元年只写数字,如「三」)—— 补全的和原文的分开放
|
||
// month/day 表给了才有;【原文没写的一律 null,不许补】
|
||
// office 官名,照录原文用字
|
||
// seat 座次(由 office 映射;见 SEATS)
|
||
// name 人名,照录原文那一格的写法
|
||
// person 规范名(按记事链解出);解不出 = null
|
||
// event 事件,用表自己的字(见 EVENTS)
|
||
// quote 引文。★ 用字照两个见证逐字比对;【标点为本项目自断】
|
||
// witnesses 2 = 两个见证逐字相同;1 = 只有一个见证
|
||
// caveat 异文/限定语。有就必须给。
|
||
// seed true = 文帝朝的接续记事,不在覆盖范围
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
|
||
const E = (o) => o; // 只为让下面每条对齐好读,不做任何事
|
||
|
||
export const GONGQING = [
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 接续用(文帝朝)—— ★ 不把这几笔放进来,courtAt(-156) 就是空的:
|
||
// 景帝元年的丞相是文帝後元二年拜的,太尉早在文帝三年就裁了。
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -179, era: '孝文元年', eraRaw: '孝文元年', month: '十月', day: '辛亥',
|
||
office: '太尉', seat: 'taiwei', name: '灌嬰', person: '灌嬰', from: '將軍', event: '拜',
|
||
quote: '十月辛亥,將軍灌嬰為太尉,二年遷,官省。',
|
||
source: BIAO, witnesses: 2, seed: true,
|
||
caveat:
|
||
'⚠ 句末「二年遷,官省」照录,【不据以计算】年份(见卷首「不许复活」第二条)。' +
|
||
'⚠ 十月在岁首,此事实际在公元前 180 年(见 CALENDAR_NOTE)。',
|
||
}),
|
||
E({
|
||
year: -177, era: '孝文三年', eraRaw: '三', month: null, day: '乙亥',
|
||
office: '太尉', seat: 'taiwei', name: '灌嬰', person: '灌嬰', event: '遷', to: '丞相',
|
||
quote: '十二月,丞相勃免。乙亥,太尉灌嬰為丞相。',
|
||
source: BIAO, witnesses: 2, seed: true,
|
||
caveat: '⚠ 「十二月」系于「丞相勃免」,灌婴迁丞相只给了日「乙亥」【未给月】。原文没写的不补,month 置 null。',
|
||
}),
|
||
E({
|
||
year: -177, era: '孝文三年', eraRaw: '三', month: null, day: null,
|
||
office: '太尉', seat: 'taiwei', name: null, person: null, event: '官省',
|
||
quote: '十月辛亥,將軍灌嬰為太尉,二年遷,官省。',
|
||
source: BIAO, witnesses: 2, seed: true, yearInferred: true,
|
||
caveat:
|
||
'★【年份是推断,不是原文】:「官省」二字在【孝文元年】灌婴拜太尉那一格的句末,表未另系年。' +
|
||
'系于孝文三年的依据是同表孝文三年「乙亥,太尉灌嬰為丞相」(灌婴是年去太尉任),' +
|
||
'且此后至景帝三年周亚夫拜太尉之间,表中【无】太尉记事。' +
|
||
'⚠ 这是本项目的推断,courtAt 会把 inferred 标出来。要翻案就翻在这一条。',
|
||
}),
|
||
E({
|
||
year: -162, era: '孝文後元二年', eraRaw: '二', month: '八月', day: '庚午',
|
||
office: '丞相', seat: 'chengxiang', name: '申屠嘉', person: '申屠嘉', from: '御史大夫', event: '拜',
|
||
quote: '八月戊戌,丞相蒼免。庚午,御史大夫申屠嘉為丞相。',
|
||
source: BIAO, witnesses: 2, seed: true,
|
||
caveat: '★ 景帝元年在任的丞相就是他。景帝二年那格的「丞相嘉」= 申屠嘉,全名由这一笔解出。',
|
||
}),
|
||
E({
|
||
year: -162, era: '孝文後元二年', eraRaw: '二', month: '八月', day: '庚午',
|
||
office: '御史大夫', seat: 'yushi', name: '陶青', person: '陶青', from: '開封侯', event: '拜',
|
||
quote: '八月庚午,開封侯陶青為御史大夫,七年遷。',
|
||
source: BIAO, witnesses: 2, seed: true,
|
||
caveat:
|
||
'★ 景帝元年在任的御史大夫就是他。' +
|
||
'⚠ 「七年遷」照录不计算 —— 他实际迁丞相在孝景二年(前155);前162+7=前155 对得上,' +
|
||
'可周亚夫那条「五年遷」【含拜年才对得上】。两种读法互斥,故一律不算。见卷首第二条。',
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 孝景元年(前156)—— 晁错起家的那一年
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -156, era: '孝景元年', eraRaw: '孝景元年', month: null, day: null,
|
||
office: '左內史', seat: null, name: '朝錯', person: '朝錯', from: '中大夫', event: '拜',
|
||
quote: '中大夫朝錯為左內史,一年遷。',
|
||
source: BIAO, witnesses: 1,
|
||
nameVariants: ['晁錯', '鼂錯'],
|
||
caveat:
|
||
'★★【异文,且是人名】:草庐本作「朝錯」,ctext 作「晁錯」—— 两个见证在这一格【不一致】。' +
|
||
'而下一年(孝景二年)那格【两个见证都作「朝錯」】。' +
|
||
'★ 更要命的是:同一个草庐本,卷四十九的【卷题】作「爰盎晁錯傳」,而该卷【正文十一处全作「鼂錯」】,' +
|
||
'一个本子里三种写法。→ 结论:朝/晁/鼂是【同一个名字的异写】,没有一个本子是自洽的。' +
|
||
'name 照录本格原文(朝錯),异写入 nameVariants,fateOf() 三种写法都认。' +
|
||
'⚠【不许】拿其中一种去「校正」另一种 —— 那是点校者的活,不是我们的活。',
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 孝景二年(前155)
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -155, era: '孝景二年', eraRaw: '二', month: '六月', day: null,
|
||
office: '丞相', seat: 'chengxiang', name: '嘉', person: '申屠嘉', event: '薨',
|
||
quote: '六月丞相嘉薨。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '「嘉」= 申屠嘉,由同表孝文後元二年「御史大夫申屠嘉為丞相」解出(见 PERSON_NOTE)。',
|
||
}),
|
||
E({
|
||
year: -155, era: '孝景二年', eraRaw: '二', month: '八月', day: '丁未',
|
||
office: '丞相', seat: 'chengxiang', name: '陶青', person: '陶青', from: '御史大夫', event: '拜',
|
||
quote: '八月丁未,御史大夫陶青為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '★ 景帝三年七国反、晁错死的那一年,在位的丞相就是他 —— 他这一格【一年没动】,故那年不出现。',
|
||
}),
|
||
E({
|
||
year: -155, era: '孝景二年', eraRaw: '二', month: '八月', day: '丁巳',
|
||
office: '御史大夫', seat: 'yushi', name: '朝錯', person: '朝錯', from: '左內史', event: '拜',
|
||
quote: '八月丁巳,左內史朝錯為御史大夫。',
|
||
source: BIAO, witnesses: 2,
|
||
nameVariants: ['晁錯', '鼂錯'],
|
||
caveat:
|
||
'★ 这一格两个见证【都作「朝錯」】,与上一年那格的异文相反。见 -156 条的说明。' +
|
||
'⚠ 拜于八月丁巳,五个月后(次年正月壬子)要斩。这两笔之间【什么都没有】——' +
|
||
'表不记他为什么死,表只记他哪天死。',
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// ★★ 孝景三年(前154)—— 这一年就是这个功能的样板。
|
||
// 七国反。你在场。而这一年表里记了七笔,笔笔要命。
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -154, era: '孝景三年', eraRaw: '三', month: '正月', day: '壬子',
|
||
office: '御史大夫', seat: 'yushi', name: '錯', person: '朝錯', event: '要斬',
|
||
quote: '正月壬子,錯有罪要斬。',
|
||
source: BIAO, witnesses: 2, officeFrom: 'column',
|
||
nameVariants: ['晁錯', '鼂錯'],
|
||
caveat:
|
||
'★★ 两个见证【逐字相同】,一个字都不差。' +
|
||
'⚠【官名是本格文字没写的】:这九个字里没有「御史大夫」四字,官名取自【表的栏】。' +
|
||
'这不算补 —— 同表上一年「八月丁巳,左內史朝錯為御史大夫」把他放在这个位子上,' +
|
||
'栏与记事链两头对得上,故 officeFrom 标 column,让读者自己判。' +
|
||
'⚠【表作「要斬」不作「腰斬」】,要通腰。照录原字。' +
|
||
'★★【「东市」不在这一卷】:本表只有这九个字,没有「东市」,没有「衣朝衣」,也没有「七国反」。' +
|
||
'那些在《汉书》卷四十九《爰盎晁錯傳》(「錯衣朝衣斬東巿」,草庐/ctext 双证)。' +
|
||
'那是【另一卷】。把传里的细节记到表的账上,正是本项目最忌的那种错。' +
|
||
'(又:两个见证该处都把「市」写作「巿」,疑为共同的编码讹字;因非本卷之事,' +
|
||
'本表不引其文,只在此说明,不替它定谳。)',
|
||
}),
|
||
E({
|
||
year: -154, era: '孝景三年', eraRaw: '三', month: null, day: null,
|
||
office: '太尉', seat: 'taiwei', name: '周亞夫', person: '周亞夫', from: '中尉', event: '拜',
|
||
quote: '中尉周亞夫為太尉,五年遷,官省。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'★★ 太尉这个位子【空了二十三年】(自文帝三年灌婴迁丞相官省),七国反的这一年才重新拜人 ——' +
|
||
'这是本表最有力的一条:官制的开合,就是战事的影子。' +
|
||
'⚠ 「五年遷,官省」照录,【不据以算年】:他实际迁丞相在景帝七年(前150),' +
|
||
'前154 算第 1 年恰是第 5 年(含拜年);可陶青那条「七年遷」【不含拜年才对】。' +
|
||
'两种读法互斥 —— 这正是「N年不可计算」那条铁律的头一个样本。',
|
||
}),
|
||
E({
|
||
year: -154, era: '孝景三年', eraRaw: '三', month: null, day: null,
|
||
office: '大將軍', seat: 'jiangjun', name: '竇嬰', person: '竇嬰', from: '故詹事', event: '拜',
|
||
quote: '故詹事竇嬰為大將軍。',
|
||
source: BIAO, witnesses: 2,
|
||
corroboration: {
|
||
what: '★ 另一卷把这一笔的【为什么】写了出来,且与本表严丝合缝',
|
||
source: '《汉书》卷四十九·爰盎晁錯傳第十九',
|
||
quote: '嬰入言,上乃召盎。盎入見,竟言吳所以反,獨急斬錯以謝吳,吳可罷。上拜盎為泰常,竇嬰為大將軍。',
|
||
caveat:
|
||
'★★ 双证(草庐 049.htm + ctext han-shu/yuan-ang-chao-cuo-zhuan),逐字相同' +
|
||
'(仅「迺/乃」一字异写)。★ 这与本表孝景三年【两格】对得上:「故吳相袁盎為奉常」与' +
|
||
'「故詹事竇嬰為大將軍」—— 表记【谁升了】,传记【为什么升】:窦婴引袁盎入见,' +
|
||
'袁盎劝景帝斩晁错以谢吴,二人当年即各得一官。' +
|
||
'⚠ 是【旁证不是本表】,属卷四十九。⚠ 卷四十九作「泰常」,本表作「奉常」——' +
|
||
'而本表自己在中元六年记「奉常利更為太常」,可见景帝三年的正式官名是奉常,' +
|
||
'卷四十九的「泰常」是随手写。⚠ 标点为本项目自断。',
|
||
},
|
||
caveat: '⚠ 本表【没有】窦婴此前的记事,「故詹事」三字是本格自带的,不是别处解出来的。',
|
||
}),
|
||
E({
|
||
year: -154, era: '孝景三年', eraRaw: '三', month: null, day: null,
|
||
office: '奉常', seat: null, name: '袁盎', person: '袁盎', from: '故吳相', event: '拜',
|
||
quote: '故吳相袁盎為奉常。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'★★ 这一格是整张表里最刺人的一格:【吴反,而他是故吴相】——那年他从反王的相,' +
|
||
'变成了朝廷的奉常。同一年,主张削吴的晁错要斩。表把这两笔【并排放在同一行】,一个字的评论都没有。' +
|
||
'(为什么升,见同年窦婴条的 corroboration:卷四十九,双证。)',
|
||
}),
|
||
E({
|
||
year: -154, era: '孝景三年', eraRaw: '三', month: null, day: null,
|
||
office: '奉常', seat: null, name: '殷', person: null, event: '拜',
|
||
quote: '奉常殷。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'⚠【姓名不具】:只有一个「殷」字,person 置 null(见 SHIGU_NOTE)。' +
|
||
'⚠ 同年同官两笔(袁盎、殷),表【不说谁先谁后】,也不给月 —— 别替它排序。',
|
||
}),
|
||
E({
|
||
year: -154, era: '孝景三年', eraRaw: '三', month: null, day: null,
|
||
office: '廷尉', seat: null, name: '勝', person: null, event: '拜',
|
||
quote: '廷尉勝。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠【姓名不具】,person 置 null。见 SHIGU_NOTE。',
|
||
}),
|
||
E({
|
||
year: -154, era: '孝景三年', eraRaw: '三', month: null, day: null,
|
||
office: '宗正', seat: null, name: '劉通', person: '劉通', from: '德侯', event: '拜',
|
||
quote: '德侯劉通為宗正,三年薨。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 「三年薨」照录,不据以算年。',
|
||
}),
|
||
E({
|
||
year: -154, era: '孝景三年', eraRaw: '三', month: null, day: null,
|
||
office: '中尉', seat: null, name: '衞綰', person: '衞綰', from: '河間大傅', event: '拜',
|
||
quote: '河間大傅衞綰為中尉,四年賜告,後為太子太傅。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'⚠ 表作「大傅」(= 太傅),照录不径改。⚠ ctext 作「衛綰」(衞/衛同字异形)。' +
|
||
'⚠ 「四年賜告」照录,不据以算年。' +
|
||
'★ 他后来做到丞相(景帝後元年),是这一年在场的人里【走得最远又善终】的一个 —— ' +
|
||
'与同年要斩的晁错正好是一对照。',
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 孝景四年—七年
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -153, era: '孝景四年', eraRaw: '四', month: null, day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '介', person: null, event: '拜',
|
||
quote: '御史大夫介。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠【姓名不具】,person 置 null。★ 接晁错位子的这个人,表只留下一个字。',
|
||
}),
|
||
E({
|
||
year: -150, era: '孝景七年', eraRaw: '七', month: '六月', day: '乙巳',
|
||
office: '丞相', seat: 'chengxiang', name: '青', person: '陶青', event: '免',
|
||
quote: '六月乙巳,丞相青免。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
E({
|
||
year: -150, era: '孝景七年', eraRaw: '七', month: null, day: null,
|
||
office: '丞相', seat: 'chengxiang', name: '周亞夫', person: '周亞夫', from: '太尉', event: '拜',
|
||
quote: '太尉周亞夫為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 同格前句「六月乙巳」系于「丞相青免」,周亚夫拜相【未给月日】。不补。',
|
||
}),
|
||
E({
|
||
year: -150, era: '孝景七年', eraRaw: '七', month: null, day: null,
|
||
office: '太尉', seat: 'taiwei', name: '周亞夫', person: '周亞夫', event: '遷', to: '丞相',
|
||
quote: '太尉周亞夫為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'★ 他离开太尉这一笔,靠的就是同格「太尉周亞夫為丞相」六个字 —— 表没有单写「太尉某免」,' +
|
||
'是这一句自己说了他从哪儿走的。courtAt 靠它把人从太尉那个位子上拿下来。',
|
||
}),
|
||
E({
|
||
year: -150, era: '孝景七年', eraRaw: '七', month: null, day: null,
|
||
office: '太尉', seat: 'taiwei', name: null, person: null, event: '官省',
|
||
quote: '中尉周亞夫為太尉,五年遷,官省。',
|
||
source: BIAO, witnesses: 2, yearInferred: true,
|
||
caveat:
|
||
'★【年份是推断】:「官省」在【景帝三年】周亚夫拜太尉那格的句末,表未另系年。' +
|
||
'系于景帝七年的依据是同表是年「太尉周亞夫為丞相」(他去了太尉任),' +
|
||
'且此后至建元元年田蚡拜太尉之间表中无太尉记事。⚠ 推断,非原文。',
|
||
}),
|
||
E({
|
||
year: -150, era: '孝景七年', eraRaw: '七', month: null, day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '劉舍', person: '劉舍', from: '太僕', event: '拜',
|
||
quote: '太僕劉舍為御史大夫,三年遷。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'⚠ 「三年遷」照录,不据以算年 —— 他实际迁丞相在中元三年(前147):含拜年是第 4 年、' +
|
||
'不含拜年是 +3。★ 这一条是「N年不可计算」的第三个样本,' +
|
||
'而且它跟周亚夫那条【两种读法都对不上同一种】。见卷首第二条。',
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 孝景中三年—後元年
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -147, era: '孝景中三年', eraRaw: '三', month: '九月', day: '戊戌',
|
||
office: '丞相', seat: 'chengxiang', name: '亞夫', person: '周亞夫', event: '免',
|
||
quote: '九月戊戌,丞相亞夫免。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '★ 表只记到「免」为止。周亚夫后来怎么死的,【不在这一卷】—— 别替表往下写。',
|
||
}),
|
||
E({
|
||
year: -147, era: '孝景中三年', eraRaw: '三', month: null, day: null,
|
||
office: '丞相', seat: 'chengxiang', name: '劉舍', person: '劉舍', from: '御史大夫', event: '拜',
|
||
quote: '御史大夫劉舍為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 同格前句的「九月戊戌」系于「丞相亞夫免」,此拜未给月日。不补。',
|
||
}),
|
||
E({
|
||
year: -147, era: '孝景中三年', eraRaw: '三', month: null, day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '衞綰', person: '衞綰', from: '太子太傅', event: '拜',
|
||
quote: '太子太傅衞綰為御史大夫,四年遷。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ ctext 作「衛綰」(同字异形)。⚠ 「四年遷」照录,不算。',
|
||
}),
|
||
E({
|
||
year: -143, era: '孝景後元年', eraRaw: '後元年', month: '七月', day: '丙午',
|
||
office: '丞相', seat: 'chengxiang', name: '舍', person: '劉舍', event: '免',
|
||
quote: '七月丙午,丞相舍免。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
E({
|
||
year: -143, era: '孝景後元年', eraRaw: '後元年', month: '八月', day: '壬辰',
|
||
office: '丞相', seat: 'chengxiang', name: '衞綰', person: '衞綰', from: '御史大夫', event: '拜',
|
||
quote: '八月壬辰,御史大夫衞綰為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ ctext 作「衛綰」。★ 景帝三年他还只是个中尉,十一年后他是丞相。',
|
||
}),
|
||
E({
|
||
year: -143, era: '孝景後元年', eraRaw: '後元年', month: '八月', day: '壬辰',
|
||
office: '御史大夫', seat: 'yushi', name: '直不疑', person: '直不疑', from: '衞尉', event: '拜',
|
||
quote: '八月壬辰,衞尉直不疑為御史大夫。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'★★【要紧异文,且关乎一个人的下场】:句末草庐本作「三年【死】」,ctext 作「三年【免】」。' +
|
||
'死与免,是死在任上还是活着离任 —— 两个见证给的是两回事。' +
|
||
'★ 故本条 quote【截到「為御史大夫」为止】,那半句两边一致;有分歧的四个字不进 quote,' +
|
||
'也【不给他 fate】。fateOf("直不疑") 只会告诉你「两个见证打架,本表不裁」。' +
|
||
'⚠ 这不是数据缺失,这是【查不实的宁可不写】在这一格的样子。',
|
||
variantUnresolved: { field: 'fate', witnessA: '三年死(草庐)', witnessB: '三年免(ctext)' },
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 孝武建元元年(前140)—— 窦婴、田蚡同时上来的那一年
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -140, era: '孝武建元元年', eraRaw: '孝武建元元年', month: '六月', day: null,
|
||
office: '丞相', seat: 'chengxiang', name: '綰', person: '衞綰', event: '免',
|
||
quote: '六月,丞相綰免。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
E({
|
||
year: -140, era: '孝武建元元年', eraRaw: '孝武建元元年', month: null, day: '丙寅',
|
||
office: '丞相', seat: 'chengxiang', name: '竇嬰', person: '竇嬰', from: '魏其侯', event: '拜',
|
||
quote: '丙寅,魏其侯竇嬰為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'⚠ 只给日「丙寅」,【未给月】。同格前句作「六月,丞相綰免」,读起来像六月丙寅,' +
|
||
'但原文没有重出月份 —— 不补,month 置 null。' +
|
||
'★ 景帝三年他是大将军,十四年后他是丞相 —— 而他这个丞相只当了几个月(见次年)。',
|
||
}),
|
||
E({
|
||
year: -140, era: '孝武建元元年', eraRaw: '孝武建元元年', month: null, day: null,
|
||
office: '太尉', seat: 'taiwei', name: '田蚡', person: '田蚡', from: '武安侯', event: '拜',
|
||
quote: '武安侯田蚡為太尉。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '★ 太尉这个位子自景帝七年裁掉,隔了十年,为他一个人又开了一次 —— 开了一年(见次年)。',
|
||
}),
|
||
E({
|
||
year: -140, era: '孝武建元元年', eraRaw: '孝武建元元年', month: null, day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '牛抵', person: '牛抵', from: '齊相', event: '拜',
|
||
quote: '齊相牛抵為御史大夫。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 孝武建元二年(前139)
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -139, era: '孝武建元二年', eraRaw: '二', month: '十月', day: null,
|
||
office: '丞相', seat: 'chengxiang', name: '嬰', person: '竇嬰', event: '免',
|
||
quote: '十月丞相嬰免。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'★★【这一格是「岁首在十月」的活证据】:十月在【三月乙未】之前 —— 同一格里十月排在三月前头,' +
|
||
'正因为汉初的年是从十月起的。' +
|
||
'⚠ 故此事实际在【公元前 140 年】十月,不是前 139 年。year 记 -139 是本表的口径' +
|
||
'(取该汉年正月所在的公历年),要实际公历年请用 gregorianYearOf()。见 CALENDAR_NOTE。',
|
||
}),
|
||
E({
|
||
year: -139, era: '孝武建元二年', eraRaw: '二', month: '三月', day: '乙未',
|
||
office: '丞相', seat: 'chengxiang', name: '許昌', person: '許昌', from: '太常', event: '拜',
|
||
quote: '三月乙未,太常許昌為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
E({
|
||
year: -139, era: '孝武建元二年', eraRaw: '二', month: null, day: null,
|
||
office: '太尉', seat: 'taiwei', name: '蚡', person: '田蚡', event: '免',
|
||
quote: '太尉蚡免,官省。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
E({
|
||
year: -139, era: '孝武建元二年', eraRaw: '二', month: null, day: null,
|
||
office: '太尉', seat: 'taiwei', name: null, person: null, event: '官省',
|
||
quote: '太尉蚡免,官省。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'★ 这一条的「官省」【是原文自带年份的】—— 与灌婴、周亚夫那两条不同,' +
|
||
'它就写在建元二年这一格里,不用推断,故【没有 yearInferred】。' +
|
||
'★★ 自此至後元二年霍光拜大司马大将军,太尉一栏【五十二年空白】。' +
|
||
'「太尉是谁」这个问题,在武帝朝大半时间里的答案是:没有这个官。',
|
||
}),
|
||
E({
|
||
year: -139, era: '孝武建元二年', eraRaw: '二', month: null, day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '趙綰', person: '趙綰', event: '自殺',
|
||
quote: '御史大夫趙綰,有罪自殺。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'⚠★【表阙】:赵绾【拜御史大夫这一笔,本表没有】—— 他是凭空出现在自己的死讯里的。' +
|
||
'上一年的御史大夫是牛抵,牛抵怎么走的表也没记。' +
|
||
'这正是顏師古说的「史之闕文,不可得知」。别替它填。',
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 孝武建元四年—六年
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -137, era: '孝武建元四年', eraRaw: '四', month: null, day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '嚴青翟', person: '嚴青翟', from: '武強侯', event: '拜',
|
||
quote: '武強侯嚴青翟為御史大夫,二年,坐竇太后喪不辦免。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 「二年……免」照录,不据以算年。★ 他后来做到丞相,然后自杀(元鼎二年)。',
|
||
}),
|
||
E({
|
||
year: -135, era: '孝武建元六年', eraRaw: '六', month: '六月', day: '癸巳',
|
||
office: '丞相', seat: 'chengxiang', name: '昌', person: '許昌', event: '免',
|
||
quote: '六月癸巳,丞相昌免。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
E({
|
||
year: -135, era: '孝武建元六年', eraRaw: '六', month: null, day: null,
|
||
office: '丞相', seat: 'chengxiang', name: '田蚡', person: '田蚡', from: '武安侯', event: '拜',
|
||
quote: '武安侯田蚡為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 同格「六月癸巳」系于「丞相昌免」,此拜未给月日。不补。',
|
||
}),
|
||
E({
|
||
year: -135, era: '孝武建元六年', eraRaw: '六', month: null, day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '韓安國', person: '韓安國', from: '大農令', event: '拜',
|
||
quote: '大農令韓安國為御史大夫,四年病免。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 「四年病免」照录,不据以算年。',
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 元光四年(前131)—— 田蚡薨
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -131, era: '元光四年', eraRaw: '四', month: '三月', day: '乙卯',
|
||
office: '丞相', seat: 'chengxiang', name: '蚡', person: '田蚡', event: '薨',
|
||
quote: '三月乙卯,丞相蚡薨。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'★ 表给田蚡的字是「薨」—— 死在丞相任上,善终的写法。' +
|
||
'⚠ 而窦婴怎么完的,【本表一个字都没有】:他建元二年免相之后就再没进过这张表。' +
|
||
'公卿年表只记公卿;你不在那个位子上,你的死不归它管。' +
|
||
'★★ 这本身就是这张表最冷的一句话。',
|
||
}),
|
||
E({
|
||
year: -131, era: '元光四年', eraRaw: '四', month: '五月', day: '丁巳',
|
||
office: '丞相', seat: 'chengxiang', name: '薛澤', person: '薛澤', from: '平棘侯', event: '拜',
|
||
quote: '五月丁巳,平棘侯薛澤為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'⚠ 异文:ctext 作「平【觉】侯」。判为 ctext 之误 —— 「觉」是简体字,混在繁体正文里,' +
|
||
'是 OCR 坏字的指纹(同页另有「風發【鲷】」同类)。从草庐作「平棘侯」。见 WITNESS_NOTE.ctextFlaws。',
|
||
}),
|
||
E({
|
||
year: -131, era: '元光四年', eraRaw: '四', month: '九月', day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '張敺', person: null, personUncertain: true, from: '中尉', event: '拜',
|
||
quote: '九月,中尉張敺為御史大夫,五年老病免,食上大夫祿。',
|
||
source: BIAO, witnesses: 2,
|
||
nameVariants: ['張歐'],
|
||
caveat:
|
||
'⚠ 异文:ctext 作「張歐」(歐/敺,顏師古于卷内注「歐讀與驅同」、卷四十九注「張𢿛也,音區」,' +
|
||
'三形同音同人)。' +
|
||
'⚠★【同名不并人,故 person 置 null】:本表【同一年】还有一笔「宣平侯張敺為太常」——' +
|
||
'一个是中尉迁御史大夫,一个是宣平侯拜太常,封邑不同,显非一人。' +
|
||
'本表另有景帝元年「廷尉歐」、景帝五年「安丘侯張歐為奉常」。这几笔是几个人,' +
|
||
'本表的记事链【串不起来】,故一律不并。见 PERSON_NOTE.homonym。' +
|
||
'⚠ 「五年老病免」照录,不算。★ 但「老病免,食上大夫祿」是这张表里少见的好下场。',
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 元光五年(前130)—— 公孙弘起家
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -130, era: '元光五年', eraRaw: '五', month: null, day: null,
|
||
office: '左內史', seat: null, name: '公孫弘', person: '公孫弘', from: '博士', event: '拜',
|
||
quote: '博士公孫弘為左內史,四年遷。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'⚠ 「四年遷」照录,不算。' +
|
||
'★ 他由【博士】起家,六年后是御史大夫,八年后是丞相 —— 这条线是本表里' +
|
||
'「一个没有军功、没有外戚身份的人能走多远」的样本。',
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 元朔三年—五年
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -126, era: '元朔三年', eraRaw: '三', month: null, day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '公孫弘', person: '公孫弘', from: '左內史', event: '拜',
|
||
quote: '左內史公孫弘為御史大夫,二年遷。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 「二年遷」照录,不算(实际迁丞相在元朔五年)。',
|
||
}),
|
||
E({
|
||
year: -126, era: '元朔三年', eraRaw: '三', month: null, day: null,
|
||
office: '廷尉', seat: null, name: '張湯', person: '張湯', from: '中大夫', event: '拜',
|
||
quote: '中大夫張湯為廷尉,五年遷。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 「五年遷」照录,不算。',
|
||
}),
|
||
E({
|
||
year: -124, era: '元朔五年', eraRaw: '五', month: '十一月', day: '乙丑',
|
||
office: '丞相', seat: 'chengxiang', name: '澤', person: '薛澤', event: '免',
|
||
quote: '十一月乙丑,丞相澤免。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 十一月在岁首之后、正月之前 → 此事实际在公元前 125 年。见 CALENDAR_NOTE。',
|
||
}),
|
||
E({
|
||
year: -124, era: '元朔五年', eraRaw: '五', month: null, day: null,
|
||
office: '丞相', seat: 'chengxiang', name: '公孫弘', person: '公孫弘', from: '御史大夫', event: '拜',
|
||
quote: '御史大夫公孫弘為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 同格「十一月乙丑」系于「丞相澤免」,此拜未给月日。不补。',
|
||
}),
|
||
E({
|
||
year: -124, era: '元朔五年', eraRaw: '五', month: '四月', day: '丁未',
|
||
office: '御史大夫', seat: 'yushi', name: '番係', person: '番係', from: '河東太守', event: '拜',
|
||
quote: '四月丁未,河東太守九江番係為御史大夫。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '「九江」是籍贯。⚠ 顏師古注「番音普安反」(是注,不入 quote)。',
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 元狩元年—六年
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -122, era: '元狩元年', eraRaw: '元狩元年', month: null, day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '李蔡', person: '李蔡', from: '樂安侯', event: '拜',
|
||
quote: '樂安侯李蔡為御史大夫,一年遷。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 「一年遷」照录,不算。',
|
||
}),
|
||
E({
|
||
year: -121, era: '元狩二年', eraRaw: '二', month: '三月', day: '戊寅',
|
||
office: '丞相', seat: 'chengxiang', name: '弘', person: '公孫弘', event: '薨',
|
||
quote: '三月戊寅,丞相弘薨。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '★ 表给公孙弘的字是「薨」:他死在丞相任上。这张表里的丞相,能拿到这个字的不多。',
|
||
}),
|
||
E({
|
||
year: -121, era: '元狩二年', eraRaw: '二', month: null, day: '壬辰',
|
||
office: '丞相', seat: 'chengxiang', name: '李蔡', person: '李蔡', from: '御史大夫', event: '拜',
|
||
quote: '壬辰,御史大夫李蔡為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 只给日「壬辰」,未给月(同格前句作「三月戊寅」)。不补。',
|
||
}),
|
||
E({
|
||
year: -120, era: '元狩三年', eraRaw: '三', month: '三月', day: '壬辰',
|
||
office: '御史大夫', seat: 'yushi', name: '張湯', person: '張湯', from: '廷尉', event: '拜',
|
||
quote: '三月壬辰,廷尉張湯為御史大夫。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'⚠ 原格句末尚有「六年有罪自殺」六字,两个见证一致;本条 quote 截到拜官为止,' +
|
||
'其自杀另出一条(见 fate 条),【年份不算,只照录】。',
|
||
fateInline: {
|
||
words: '六年有罪自殺',
|
||
quote: '三月壬辰,廷尉張湯為御史大夫,六年有罪自殺。',
|
||
caveat:
|
||
'★【下场写在拜官那一格里】:表的惯例是把结局压缩进任命句尾。' +
|
||
'⚠ 故张汤【死于哪一年,本表算不出来】——「六年」是那个不可计算的记法。' +
|
||
'fateOf("張湯") 会给你「自殺」这个结局,year 一律 null。' +
|
||
'(《汉书》卷六·武帝纪元鼎二年另有「御史大夫張湯有罪,自殺」,那是【另一卷】,' +
|
||
'本表不据以补年 —— 要补,得先按本项目的规矩把那一卷也做两个见证。)',
|
||
},
|
||
}),
|
||
E({
|
||
year: -120, era: '元狩三年', eraRaw: '三', month: null, day: null,
|
||
office: '票騎將軍', seat: 'jiangjun', name: '霍去病', person: '霍去病', from: '冠軍侯', event: '拜',
|
||
quote: '冠軍侯霍去病為票騎將軍。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 表作「票騎」不作「驃騎」。照录原字。',
|
||
}),
|
||
E({
|
||
year: -119, era: '元狩四年', eraRaw: '四', month: null, day: null,
|
||
office: '大司馬大將軍', seat: 'taiwei', name: '衞青', person: '衞青', from: '大將軍', event: '拜',
|
||
quote: '大將軍衞青為大司馬大將軍。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'⚠ ctext 作「衛青」(同字异形)。' +
|
||
'⚠★【表阙的活证据】:这一格管卫青叫「大將軍」,可【卫青拜大将军那一笔,本表从头到尾没有】。' +
|
||
'一个大将军凭空出现在他升迁的那一格里 —— 这就是列将军栏不能当名单的原因。见 COVERAGE.jiangjun。' +
|
||
'⚠ 「大司马」放在太尉栏,是【原表的编排】,不是本文件对二者关系的判断。见 SEATS.taiwei。',
|
||
}),
|
||
E({
|
||
year: -119, era: '元狩四年', eraRaw: '四', month: null, day: null,
|
||
office: '大司馬票騎將軍', seat: 'taiwei', name: '霍去病', person: '霍去病', from: '票騎將軍', event: '拜',
|
||
quote: '票騎將軍霍去病為大司馬票騎將軍。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '★ 与卫青同格同年 —— 太尉那一栏,这一年头一回同时坐了两个人。',
|
||
}),
|
||
E({
|
||
year: -118, era: '元狩五年', eraRaw: '五', month: '三月', day: '甲午',
|
||
office: '丞相', seat: 'chengxiang', name: '蔡', person: '李蔡', event: '自殺',
|
||
quote: '三月甲午,丞相蔡有罪自殺。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
E({
|
||
year: -118, era: '元狩五年', eraRaw: '五', month: '四月', day: '乙卯',
|
||
office: '丞相', seat: 'chengxiang', name: '嚴青翟', person: '嚴青翟', from: '太子少傅', event: '拜',
|
||
quote: '四月乙卯,太子少傅嚴青翟為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
E({
|
||
year: -117, era: '元狩六年', eraRaw: '六', month: '九月', day: null,
|
||
office: '大司馬票騎將軍', seat: 'taiwei', name: '去病', person: '霍去病', event: '薨',
|
||
quote: '九月,大司馬去病薨。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 元鼎二年—六年
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -115, era: '元鼎二年', eraRaw: '二', month: '二月', day: '壬辰',
|
||
office: '丞相', seat: 'chengxiang', name: '青翟', person: '嚴青翟', event: '自殺',
|
||
quote: '二月壬辰,丞相青翟有罪自殺。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '★ 连着两任丞相「有罪自殺」(李蔡、严青翟)。表不评论,表只是一笔一笔地记。',
|
||
}),
|
||
E({
|
||
year: -115, era: '元鼎二年', eraRaw: '二', month: '二月', day: '辛亥',
|
||
office: '丞相', seat: 'chengxiang', name: '趙周', person: '趙周', from: '太子太傅', event: '拜',
|
||
quote: '二月辛亥,太子太傅趙周為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
E({
|
||
year: -115, era: '元鼎二年', eraRaw: '二', month: '二月', day: '辛亥',
|
||
office: '御史大夫', seat: 'yushi', name: '石慶', person: '石慶', from: '太子太傅', event: '拜',
|
||
quote: '二月辛亥,太子太傅石慶為御史大夫,三年遷。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 「三年遷」照录,不算。⚠ 与赵周同日(二月辛亥)、同出太子太傅 —— 表如此,不深说。',
|
||
}),
|
||
E({
|
||
year: -112, era: '元鼎五年', eraRaw: '五', month: '九月', day: '辛巳',
|
||
office: '丞相', seat: 'chengxiang', name: '周', person: '趙周', event: '下獄死',
|
||
quote: '九月辛巳,丞相周下獄死。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
E({
|
||
year: -112, era: '元鼎五年', eraRaw: '五', month: null, day: '丙申',
|
||
office: '丞相', seat: 'chengxiang', name: '石慶', person: '石慶', from: '御史大夫', event: '拜',
|
||
quote: '丙申,御史大夫石慶為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 只给日,未给月(同格前句作「九月辛巳」)。不补。',
|
||
}),
|
||
E({
|
||
year: -111, era: '元鼎六年', eraRaw: '六', month: null, day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '卜式', person: '卜式', from: '齊相', event: '拜',
|
||
quote: '齊相卜式為御史大夫,一年貶為太子太傅。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 「一年貶」照录,不算。',
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 元封元年—五年
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -110, era: '元封元年', eraRaw: '元封元年', month: null, day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '兒寬', person: '兒寬', from: '左內史', event: '拜',
|
||
quote: '左內史兒寬為御史大夫,八年卒。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 「八年卒」照录,不算。★ 御史大夫这个位子上,能拿到「卒」字(死在任上、无罪)的不多。',
|
||
}),
|
||
E({
|
||
year: -106, era: '元封五年', eraRaw: '五', month: null, day: null,
|
||
office: '大司馬大將軍', seat: 'taiwei', name: '青', person: '衞青', event: '薨',
|
||
quote: '大將軍青薨。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'⚠ 表这里称他「大將軍」而非「大司馬大將軍」,office 取其元狩四年所拜之全名。' +
|
||
'⚠ ctext 作「衛青」。',
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 太初二年—三年
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -103, era: '太初二年', eraRaw: '二', month: '正月', day: '戊寅',
|
||
office: '丞相', seat: 'chengxiang', name: '慶', person: '石慶', event: '薨',
|
||
quote: '正月戊寅,丞相慶薨。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '★ 太初元年已改历(以正月为岁首),故此后「正月」就是岁首。见 CALENDAR_NOTE。',
|
||
}),
|
||
E({
|
||
year: -103, era: '太初二年', eraRaw: '二', month: '閏月', day: '丁丑',
|
||
office: '丞相', seat: 'chengxiang', name: '公孫賀', person: '公孫賀', from: '大僕', event: '拜',
|
||
quote: '閏月丁丑,大僕公孫賀為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 表作「大僕」(= 太僕),照录不径改。⚠ 「閏月」照录,本表不推它是闰几月。',
|
||
}),
|
||
E({
|
||
year: -102, era: '太初三年', eraRaw: '三', month: '正月', day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '延廣', person: '延廣', from: '膠東太守', event: '拜',
|
||
quote: '正月,膠東太守延廣為御史大夫。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 天漢元年—三年
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -100, era: '天漢元年', eraRaw: '天漢元年', month: null, day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '王卿', person: '王卿', from: '濟南太守', event: '拜',
|
||
quote: '濟南太守琅邪王卿為御史大夫,二年有罪自殺。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '「琅邪」是籍贯。⚠ 「二年有罪自殺」照录,不算。',
|
||
fateInline: { words: '二年有罪自殺', quote: '濟南太守琅邪王卿為御史大夫,二年有罪自殺。' },
|
||
}),
|
||
E({
|
||
year: -98, era: '天漢三年', eraRaw: '三', month: '二月', day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '杜周', person: '杜周', from: '執金吾', event: '拜',
|
||
quote: '二月,執金吾杜周為御史大夫,四年卒。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 「四年卒」照录,不算。',
|
||
fateInline: { words: '四年卒', quote: '二月,執金吾杜周為御史大夫,四年卒。' },
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 太始三年
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -94, era: '太始三年', eraRaw: '三', month: '三月', day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '暴勝之', person: '暴勝之', from: '光祿大夫', event: '拜',
|
||
quote: '三月,光祿大夫河東暴勝之公子為御史大夫,三年下獄自殺。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'「河東」是籍贯,「公子」是字(顏師古注「公子,亦勝之字也」—— 是注,不入 quote)。' +
|
||
'⚠ 「三年下獄自殺」照录,不算。',
|
||
fateInline: { words: '三年下獄自殺', quote: '三月,光祿大夫河東暴勝之公子為御史大夫,三年下獄自殺。' },
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 征和二年—四年 —— 巫蛊。这三年表里全是「下獄」「要斬」「祝詛」。
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -91, era: '征和二年', eraRaw: '二', month: '四月', day: '壬申',
|
||
office: '丞相', seat: 'chengxiang', name: '賀', person: '公孫賀', event: '下獄死',
|
||
quote: '四月壬申,丞相賀下獄死。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
E({
|
||
year: -91, era: '征和二年', eraRaw: '二', month: '五月', day: '丁巳',
|
||
office: '左丞相', seat: 'chengxiang', name: '劉屈氂', person: '劉屈氂', from: '涿郡太守', event: '拜',
|
||
quote: '五月丁巳,涿郡太守劉屈氂為左丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 表作【左丞相】,不是丞相 —— 照录,不许径写成「丞相」。',
|
||
}),
|
||
E({
|
||
year: -91, era: '征和二年', eraRaw: '二', month: '九月', day: null,
|
||
office: '御史大夫', seat: 'yushi', name: '商丘成', person: '商丘成', from: '大鴻臚', event: '拜',
|
||
quote: '九月,大鴻臚商丘成為御史大夫,四年坐祝詛自殺。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 「四年坐祝詛自殺」照录,不算。',
|
||
fateInline: { words: '四年坐祝詛自殺', quote: '九月,大鴻臚商丘成為御史大夫,四年坐祝詛自殺。' },
|
||
}),
|
||
E({
|
||
year: -90, era: '征和三年', eraRaw: '三', month: '六月', day: '壬寅',
|
||
office: '左丞相', seat: 'chengxiang', name: '屈氂', person: '劉屈氂', event: '要斬',
|
||
quote: '六月壬寅,丞相屈氂下獄要斬。',
|
||
source: BIAO, witnesses: 2,
|
||
corroboration: {
|
||
what: '★ 另一卷同记,且同用「要斬」二字',
|
||
source: '《汉书》卷六·武帝纪第六',
|
||
quote: '六月,丞相屈氂下獄要斬,妻梟首。',
|
||
caveat:
|
||
'⚠ 单证(草庐 006.htm),未取第二见证。⚠ 是【另一卷】,引作旁证。⚠ 标点为本项目自断。' +
|
||
'★ 两卷同用「要斬」,可与晁错条互看:本表全篇只有这两个人拿到这两个字。',
|
||
},
|
||
caveat:
|
||
'⚠ 本格作「丞相屈氂」,而他拜的是【左丞相】(征和二年)。表自己前后不一,照录两处原文,不调和。' +
|
||
'★★ 这是本表第二个「要斬」—— 头一个是晁错(景帝三年正月壬子)。' +
|
||
'相隔六十四年,同一个词,同一张表。',
|
||
}),
|
||
E({
|
||
year: -89, era: '征和四年', eraRaw: '四', month: '六月', day: '丁巳',
|
||
office: '丞相', seat: 'chengxiang', name: '田千秋', person: '田千秋', from: '大鴻臚', event: '拜',
|
||
quote: '六月丁巳,大鴻臚田千秋為丞相。',
|
||
source: BIAO, witnesses: 2,
|
||
}),
|
||
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
// 後元二年(前87)—— 武帝崩。本表覆盖到此为止。
|
||
// ────────────────────────────────────────────────────────────────────────
|
||
E({
|
||
year: -87, era: '後元二年', eraRaw: '二', month: null, day: '丁卯',
|
||
office: '大司馬大將軍', seat: 'taiwei', name: '霍光', person: '霍光', from: '侍中奉車都尉', event: '拜',
|
||
quote: '丁卯,侍中奉車都尉霍光為大司馬大將軍。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat:
|
||
'★★【要紧异文:月份】草庐本作「【三月】丁卯」,ctext 作「【二月】丁卯」。' +
|
||
'★ 旁证(不裁决,只摆出来):《汉书》卷六·武帝纪正文作「二月,行幸盩厔五柞宮……' +
|
||
'丁卯,帝崩于五柞宮……三月甲申,葬茂陵」——【二月丁卯是武帝崩的那一天】,' +
|
||
'而三月甲申是葬日;丁卯到甲申恰十七日,与「二月末崩、三月中葬」相合。' +
|
||
'若作三月丁卯,则在二月丁卯之后整六十日、葬后四十余日,霍光受遗诏就说不通了。' +
|
||
'⚠★ 但这是【本项目的推算】,不是史料的裁断 —— 故 month 一律置 null,' +
|
||
'两说并陈,不替读者选。要坐实,得先按规矩把武帝纪也做两个见证。' +
|
||
'★ 又:太尉那一栏自建元二年官省,空了五十二年,到武帝断气这一天才又坐上人。',
|
||
variantUnresolved: { field: 'month', witnessA: '三月(草庐)', witnessB: '二月(ctext)' },
|
||
}),
|
||
E({
|
||
year: -87, era: '後元二年', eraRaw: '二', month: '二月', day: '乙卯',
|
||
office: '御史大夫', seat: 'yushi', name: '桑弘羊', person: '桑弘羊', from: '搜粟都尉', event: '拜',
|
||
quote: '二月乙卯,搜粟都尉桑弘羊為御史大夫,七年坐謀反誅。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 「七年坐謀反誅」照录,不算 —— 那已是昭帝朝的事,【不在本表覆盖范围】。',
|
||
fateInline: { words: '七年坐謀反誅', quote: '二月乙卯,搜粟都尉桑弘羊為御史大夫,七年坐謀反誅。' },
|
||
}),
|
||
E({
|
||
year: -87, era: '後元二年', eraRaw: '二', month: null, day: null,
|
||
office: '車騎將軍', seat: 'jiangjun', name: '金日磾', person: '金日磾', from: '侍中駙馬都尉', event: '拜',
|
||
quote: '侍中駙馬都尉金日磾為車騎將軍,一年薨。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 「一年薨」照录,不算。',
|
||
fateInline: { words: '一年薨', quote: '侍中駙馬都尉金日磾為車騎將軍,一年薨。' },
|
||
}),
|
||
E({
|
||
year: -87, era: '後元二年', eraRaw: '二', month: null, day: null,
|
||
office: '左將軍', seat: 'jiangjun', name: '上官桀', person: '上官桀', from: '太僕', event: '拜',
|
||
quote: '太僕上官桀為左將軍,七年反,誅。',
|
||
source: BIAO, witnesses: 2,
|
||
caveat: '⚠ 「七年反,誅」照录,不算 —— 昭帝朝事,不在覆盖范围。',
|
||
fateInline: { words: '七年反,誅', quote: '太僕上官桀為左將軍,七年反,誅。' },
|
||
}),
|
||
];
|
||
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
// 纯函数
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
|
||
// ── 纪年 ↔ 公历 ──
|
||
|
||
// 那一年是谁的天下、纪年怎么写。year: -154 → 「孝景三年」。
|
||
export function eraAt(year) {
|
||
const y = Number(year);
|
||
if (!Number.isInteger(y)) return null;
|
||
const e = ALL_ERAS.find((x) => y >= x.from && y <= x.to);
|
||
if (!e) return null;
|
||
const n = y - e.from + 1;
|
||
return {
|
||
rulerId: e.rulerId,
|
||
rulerName: e.rulerName,
|
||
eraKey: e.key,
|
||
eraName: e.name,
|
||
n,
|
||
// 表在改元那年写全,其余年只写数字 —— label 是【本项目补全的】完整写法
|
||
label: n === 1 ? e.raw : `${e.key}${numCn(n)}年`,
|
||
labelNote: '★ 这是本项目补全的写法:表在非改元年只写数字(如「三」)。',
|
||
raw: n === 1 ? e.raw : numCn(n),
|
||
seedOnly: !!e.seedOnly,
|
||
covered: y >= COVERAGE.years.from && y <= COVERAGE.years.to,
|
||
};
|
||
}
|
||
|
||
// 「孝景」+ 3 → -154。eraKey 见 RULERS[].eras[].key。
|
||
export function yearOfEra(eraKey, n) {
|
||
const e = ALL_ERAS.find((x) => x.key === eraKey);
|
||
if (!e) return null;
|
||
const k = Number(n);
|
||
if (!Number.isInteger(k) || k < 1 || k > e.count) return null;
|
||
return e.from + k - 1;
|
||
}
|
||
|
||
const CN = ['', '元', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
|
||
function numCn(n) {
|
||
if (n <= 10) return CN[n];
|
||
if (n < 20) return `十${CN[n - 10]}`;
|
||
return `${CN[Math.floor(n / 10)]}十${n % 10 ? CN[n % 10] : ''}`;
|
||
}
|
||
|
||
// ★★ 十月岁首的修正 —— CALENDAR_NOTE.suiShou 的可执行形式。
|
||
//
|
||
// ⚠ 为什么必须有这个函数而不能只写在注释里:year 字段长得就像公历年,
|
||
// 谁都会直接拿去减、拿去画时间轴。「建元二年十月窦婴免相」的 year 是 -139,
|
||
// 而那个十月【实际在公元前 140 年】。规矩写在注释里没用,写成函数才算数
|
||
// (与 decisions.js 的 assertNoGameMechanics 同性质)。
|
||
export function gregorianYearOf(entry) {
|
||
if (!entry || !Number.isInteger(entry.year)) return null;
|
||
const winter = entry.month === '十月' || entry.month === '十一月' || entry.month === '十二月';
|
||
// 太初元年(前104)夏五月「正歷,以正月為歲首」→ 此后十月不再是岁首,无须修正。
|
||
const beforeReform = entry.year < CALENDAR_NOTE.taichuYear;
|
||
if (winter && beforeReform) {
|
||
return {
|
||
year: entry.year - 1,
|
||
adjusted: true,
|
||
why:
|
||
`太初改历前以十月为岁首:${entry.era}的十月/十一月/十二月落在【前一个公历年】。` +
|
||
`本条 year=${entry.year} 是该汉年正月所在的公历年,其实际公历年是 ${entry.year - 1}。`,
|
||
};
|
||
}
|
||
return { year: entry.year, adjusted: false, why: '' };
|
||
}
|
||
|
||
// ── courtAt:那一年,你身边站着谁 ──
|
||
//
|
||
// ⚠ 这张表是【记事链】不是花名册:它只记变动。景帝三年那一行【没有丞相】,
|
||
// 因为丞相陶青是景帝二年八月拜的,那年他没动。→ 只能重放,不能查表。
|
||
// (与 decisions.js 的 replay() 同一个道理:状态量不可直接写,只能由链推出。)
|
||
//
|
||
// ★★【重放的前提是链完整 —— 链不完整的栏,重放出来的是假的】
|
||
// 这一条是本函数最要紧的设计,也是先写测试才发现的:
|
||
// · 三公(丞相/太尉·大司马/御史大夫)的链是全的(COVERAGE.sangong.complete),
|
||
// 故【可以】把上一年的在任者接下来。
|
||
// · 列将军的链【是破的】——「大將軍衞青為大司馬大將軍」,而卫青拜大将军那一笔表里根本没有;
|
||
// 窦婴景帝三年拜大将军之后,表也从没记过他何时去职。
|
||
// 若照三公那样接下来,courtAt(前100) 会一本正经地告诉你「大将军是窦婴」——
|
||
// 窦婴那时候早就不在了,只是这张表没说。★ 那不是数据少,那是【编出来的】。
|
||
// · 九卿同理:只抠了两处(见 COVERAGE.jiuqing)。
|
||
// → 故:三公【接】,列将军与九卿【只报表在那一年记了的,不接】。
|
||
//
|
||
// ⚠ 年内先后:表在很多格【不给月】,同一年的两笔谁先谁后【不可知】。
|
||
// 故本函数给的是【那一年在过这个位子上的人】(holders),不是「某月某日的那一个」。
|
||
// 景帝三年的御史大夫就是晁错 —— 哪怕他正月壬子就要斩了。他在场。这才是这个功能要的答案。
|
||
export function courtAt(year) {
|
||
const y = Number(year);
|
||
const era = eraAt(y);
|
||
if (!era) return null;
|
||
|
||
const single = new Set(['chengxiang', 'yushi']); // 单座:新任即代前任
|
||
const lists = { chengxiang: [], taiwei: [], yushi: [], jiangjun: [] };
|
||
const others = [];
|
||
const abolished = {};
|
||
|
||
const recOf = (e) => ({
|
||
office: e.office, name: e.name, person: e.person ?? null,
|
||
personUncertain: !!e.personUncertain,
|
||
since: e.year, sinceEra: e.era, month: e.month ?? null, day: e.day ?? null,
|
||
from: e.from ?? null, quote: e.quote, source: e.source,
|
||
witnesses: e.witnesses, caveat: e.caveat ?? '', left: null,
|
||
});
|
||
// ⚠ 只有确实是他才拿下来 —— 表里同官同名的坑见 PERSON_NOTE.homonym
|
||
const matches = (r, e) =>
|
||
!r.left && ((e.person && r.person && r.person === e.person) || (!e.person && r.name === e.name));
|
||
|
||
for (const e of GONGQING) {
|
||
if (e.year > y) break; // GONGQING 按年升序(assertGongqingInvariants 守着)
|
||
|
||
if (e.event === '官省') {
|
||
// ⚠【官省是【那个官】被裁,不是【那一栏】空了】:太尉官省之后,大司马照样坐在同一栏里。
|
||
// 把它记在栏上,courtAt(前110) 就会说「太尉栏:不载」——可太尉明明是【裁了】,
|
||
// 而那一栏坐着大司马卫青。故 abolished 按【官】记,不按栏记。(先写测试才发现的。)
|
||
abolished[e.office] = {
|
||
office: e.office, seat: e.seat ?? null, since: e.year, sinceEra: e.era,
|
||
quote: e.quote, inferred: !!e.yearInferred, source: e.source, caveat: e.caveat ?? '',
|
||
};
|
||
continue;
|
||
}
|
||
|
||
const list = e.seat ? lists[e.seat] : others;
|
||
|
||
if (e.event === '拜') {
|
||
if (e.seat && single.has(e.seat)) {
|
||
const prev = list.find((r) => !r.left);
|
||
if (prev) {
|
||
prev.left = {
|
||
year: e.year, era: e.era, event: '代', month: null, day: null,
|
||
quote: e.quote,
|
||
note: '⚠ 表【没有】单写他怎么去的 —— 由后任的拜官记录推出他此时已去。',
|
||
};
|
||
}
|
||
}
|
||
list.push(recOf(e));
|
||
continue;
|
||
}
|
||
|
||
if (TERMINAL_WORDS.has(e.event)) {
|
||
const r = list.find((x) => matches(x, e));
|
||
const left = {
|
||
year: e.year, era: e.era, event: e.event, month: e.month ?? null, day: e.day ?? null,
|
||
quote: e.quote, source: e.source, caveat: e.caveat ?? '',
|
||
};
|
||
if (r) r.left = left;
|
||
else {
|
||
// ★ 表只记了他的结局,没记他的拜 —— 赵绾就是这样:凭空出现在自己的死讯里。
|
||
list.push({
|
||
...recOf(e), since: null, sinceEra: null,
|
||
sinceNote:
|
||
'★★【表阙】:本表【没有】他拜此官的记录 —— 他是凭空出现在自己的结局里的。' +
|
||
'这正是顏師古说的「史之闕文,不可得知」。见 SHIGU_NOTE。',
|
||
left,
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
// 那一年在过这个位子上的人:拜于此年之前(或此年)、且去于此年之后(或此年、或根本没去)
|
||
const held = (r) => (r.since === null || r.since <= y) && (!r.left || r.left.year >= y);
|
||
// ⚠ 链不完整的栏不许接 —— 只报表在那一年【自己记了】的
|
||
const thisYearOnly = (r) => r.since === y || (r.left && r.left.year === y);
|
||
|
||
const seatOut = (id) => {
|
||
const holders = lists[id].filter(held);
|
||
const gone = Object.values(abolished).filter((a) => a.seat === id);
|
||
let status = 'held';
|
||
if (!holders.length) status = gone.length ? '省' : '不載';
|
||
return {
|
||
holders,
|
||
abolished: gone,
|
||
status,
|
||
note:
|
||
status === '省'
|
||
? `★ 这个位子【裁了】:${gone.map((a) => `${a.office}(${a.sinceEra}官省)`).join('、')}。不是没人,是没这个官。`
|
||
: status === '不載'
|
||
? '★ 表在这一年【没有】这个位子的在任记事。不载 ≠ 无人 —— 见 SHIGU_NOTE。'
|
||
: '',
|
||
};
|
||
};
|
||
|
||
return {
|
||
year: y,
|
||
era,
|
||
ruler: { id: era.rulerId, name: era.rulerName },
|
||
// 三公(照表的栏分,非制度判断 —— 见 SEATS.taiwei.note)
|
||
chengxiang: seatOut('chengxiang'),
|
||
taiwei: seatOut('taiwei'),
|
||
yushi: seatOut('yushi'),
|
||
// ★ 不接:链是破的。见本函数顶上那一段。
|
||
jiangjun: lists.jiangjun.filter(thisYearOnly),
|
||
others: others.filter(thisYearOnly),
|
||
coverage: {
|
||
sangong: COVERAGE.sangong.complete && era.covered,
|
||
jiangjun: false,
|
||
others: false,
|
||
inRange: era.covered,
|
||
carryForward:
|
||
'★ 三公【接了】上一年的在任者(链是全的);列将军与九卿【没接】,' +
|
||
'只报表在这一年自己记了的 —— 链不完整的栏,接出来的是编的。',
|
||
note: era.covered
|
||
? COVERAGE.sangong.note
|
||
: `⚠ ${era.label} 不在覆盖范围(${COVERAGE.yearsNote})。此处只有接续用的记事,【不许当数】。`,
|
||
},
|
||
withinYearNote:
|
||
'⚠ 表在很多格不给月份,同一年两笔的先后【不可知】。故这里给的是' +
|
||
'【那一年在过这个位子上的人】,不是「某月某日的那一个」—— 不许拿 holders 的顺序排先后。',
|
||
othersNote: COVERAGE.jiuqing.note,
|
||
};
|
||
}
|
||
|
||
// ── fateOf:这个人后来怎么了 ──
|
||
//
|
||
// ★ 下卷记了大量「免」「薨」「下獄死」「要斬」—— 这个函数就是把它们摊开。
|
||
// ⚠ 表有【两种】写下场的办法,必须都认:
|
||
// (1) 单独一笔,有年有月:「正月壬子,錯有罪要斬。」→ 年份是硬的。
|
||
// (2) 压在拜官句尾:「廷尉張湯為御史大夫,六年有罪自殺。」→ 年份是那个【不可计算】的记法。
|
||
// 故 fateOf 返回的 end.year 在第二种情况下【一律 null】—— 那不是偷懒,那是卷首第二条铁律。
|
||
export function fateOf(name) {
|
||
const q = String(name || '').trim();
|
||
if (!q) return null;
|
||
const hit = (e) =>
|
||
e.person === q || e.name === q || (e.nameVariants || []).includes(q);
|
||
const entries = GONGQING.filter(hit);
|
||
if (!entries.length) {
|
||
return {
|
||
query: q, found: false, entries: [],
|
||
note: '★ 本表【没有】这个人。⚠ 不载 ≠ 没这个人 —— 公卿年表只记公卿,' +
|
||
'你不在那个位子上,你的事不归它管(窦婴免相之后就是这样)。见 COVERAGE。',
|
||
};
|
||
}
|
||
const person = entries.find((e) => e.person)?.person || null;
|
||
const variants = [...new Set(entries.flatMap((e) => [e.name, ...(e.nameVariants || [])]).filter(Boolean))];
|
||
|
||
// 结局:先找单独记下来的终结事件(年份硬)
|
||
const term = entries.filter((e) => TERMINAL_WORDS.has(e.event) && e.event !== '官省');
|
||
let end = null;
|
||
if (term.length) {
|
||
const last = term[term.length - 1];
|
||
end = {
|
||
word: last.event, year: last.year, era: last.era, month: last.month ?? null, day: last.day ?? null,
|
||
office: last.office, quote: last.quote, source: last.source,
|
||
yearReliable: true,
|
||
caveat: last.caveat ?? '',
|
||
};
|
||
} else {
|
||
// 再找压在拜官句尾的
|
||
const inline = entries.filter((e) => e.fateInline);
|
||
if (inline.length) {
|
||
const last = inline[inline.length - 1];
|
||
end = {
|
||
word: last.fateInline.words, year: null, era: null, month: null, day: null,
|
||
office: last.office, quote: last.fateInline.quote, source: last.source,
|
||
yearReliable: false,
|
||
yearNote:
|
||
'★ 年份【算不出来】:下场压在拜官句尾,只给了「若干年」。' +
|
||
'实测三个样本(周亚夫/陶青/刘舍)两种读法互斥,故本表一律不算。见卷首「不许复活」第二条。',
|
||
caveat: last.fateInline.caveat ?? '',
|
||
};
|
||
}
|
||
}
|
||
|
||
// 两个见证打架而本表不裁的(直不疑)
|
||
const unresolved = entries.filter((e) => e.variantUnresolved).map((e) => ({
|
||
year: e.year, era: e.era, office: e.office, ...e.variantUnresolved, caveat: e.caveat,
|
||
}));
|
||
|
||
return {
|
||
query: q, found: true, person, variants,
|
||
entries: entries.map((e) => ({
|
||
year: e.year, era: e.era, month: e.month ?? null, day: e.day ?? null,
|
||
office: e.office, from: e.from ?? null, event: e.event,
|
||
quote: e.quote, source: e.source, witnesses: e.witnesses, caveat: e.caveat ?? '',
|
||
seed: !!e.seed,
|
||
})),
|
||
end,
|
||
unresolved,
|
||
note:
|
||
end
|
||
? ''
|
||
: '⚠ 本表【没记他怎么完的】。不载 ≠ 善终 —— 表只管你在位子上那段。' +
|
||
'(田蚡「薨」有记,窦婴免相后一个字都没有 —— 这就是这张表最冷的地方。)',
|
||
};
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
// ★★ eventsAt(year) —— 那一年,表里记了什么事
|
||
//
|
||
// courtAt 给的是【谁在场】(状态),eventsAt 给的是【那一年发生了什么】(事件)。
|
||
// 两个是不同的问题,都得有人答:
|
||
// courtAt(-154) → 丞相陶青(景帝二年拜的,那年没动,故那一格里没有他)
|
||
// eventsAt(-154) → 正月壬子,錯有罪要斬。—— 陶青不在这里,因为他那年没出事。
|
||
//
|
||
// ★★【一个人在你眼前被腰斩,那就是大事件】—— 这就是本函数存在的理由:
|
||
// 表已经把「免/薨/下獄死/要斬/自殺/誅」这七八个字分得清清楚楚(见 EVENTS),
|
||
// 本函数只是把它们按年摊开。⚠ 它【一个字都不新增】,只是换个索引读同一份 GONGQING。
|
||
//
|
||
// ⚠⚠【本函数不生成关口】—— 这一条是本文件文件头逐字写的,别在这儿加:
|
||
// 「但本文件【不生成关口】,它只提供事实。生成是别人的事,别在这儿加。」
|
||
// ⇒ 本函数返回【事实】:那一年表记了哪几笔、哪几笔是有人完了。
|
||
// 「景帝三年 + 中大夫 + 晁错在场 ⇒ 这是个关口」——那一步的判断【不在这儿】。
|
||
//
|
||
// ★★★【空 ≠ 没事】—— 这是本函数最要紧的一句,也是「零命中比单证更危险」的同一族:
|
||
// events 是空的,意思是【表在这一年没记事】,不是【那一年太平无事】。
|
||
// 本表只记【变动】,且九卿栏只抠了两处(COVERAGE.jiuqing)。
|
||
// ⇒ 故 empty 时必须给 emptyNote,【绝不许】让前端读成「这一年没有大事」。
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
export function eventsAt(year) {
|
||
const y = Number(year);
|
||
const era = eraAt(y);
|
||
if (!era) return null;
|
||
|
||
const rows = GONGQING.filter((e) => e.year === y);
|
||
|
||
const out = rows.map((e) => {
|
||
const def = EVENTS.find((x) => x.word === e.event) || null;
|
||
const g = gregorianYearOf(e);
|
||
return {
|
||
era: e.era,
|
||
eraRaw: e.eraRaw,
|
||
month: e.month ?? null,
|
||
day: e.day ?? null,
|
||
office: e.office,
|
||
seat: e.seat ?? null,
|
||
name: e.name ?? null,
|
||
person: e.person ?? null,
|
||
personUncertain: !!e.personUncertain,
|
||
from: e.from ?? null,
|
||
to: e.to ?? null,
|
||
// ★ 用【表自己的字】。✗ 不许翻译成「离职/任命」——那样这张表最值钱的东西
|
||
// (一个人【怎么】完的)就没了。见 EVENTS 那段注。
|
||
event: e.event,
|
||
eventGloss: def?.gloss || '',
|
||
// ★ 有人完了(免/薨/卒/死/自殺/要斬/下獄死/誅),不含「官省」(那是官没了,不是人完了)
|
||
terminal: TERMINAL_WORDS.has(e.event) && e.event !== '官省',
|
||
abolition: e.event === '官省',
|
||
quote: e.quote,
|
||
source: e.source,
|
||
witnesses: e.witnesses,
|
||
caveat: e.caveat ?? '',
|
||
corroboration: e.corroboration ?? null,
|
||
variantUnresolved: e.variantUnresolved ?? null,
|
||
seed: !!e.seed,
|
||
// ★ 年份是推断不是原文的,标出来(灌婴/周亚夫那两条「官省」)
|
||
yearInferred: !!e.yearInferred,
|
||
// ★★ 十月岁首:year 长得就像公历年,谁都会拿去减 —— 故把修正结果一起给出来。
|
||
gregorian: g,
|
||
};
|
||
});
|
||
|
||
const terminal = out.filter((e) => e.terminal);
|
||
|
||
return {
|
||
year: y,
|
||
era,
|
||
ruler: { id: era.rulerId, name: era.rulerName },
|
||
events: out,
|
||
// ★ 这一年【有人完了】的那几笔 —— 「一个人在你眼前被腰斩」的那个「腰斩」。
|
||
terminal,
|
||
// 「官省」:这个官【裁了】。★ 太尉一栏大半个世纪都是这两个字。
|
||
abolished: out.filter((e) => e.abolition),
|
||
covered: era.covered,
|
||
coverage: {
|
||
inRange: era.covered,
|
||
sangong: COVERAGE.sangong.complete && era.covered,
|
||
jiuqing: false,
|
||
jiangjun: false,
|
||
note: era.covered
|
||
? '★ 三公(丞相/太尉·大司马/御史大夫)这三栏在本表覆盖年内【一格没落】,' +
|
||
'故三公的事是全的。⚠ 九卿只抠了两处、列将军是散记(见 othersNote)——' +
|
||
'那两栏【没记 ≠ 没发生】。'
|
||
: `⚠ ${era.label} 不在覆盖范围(${COVERAGE.yearsNote})。此处只有接续用的记事,【不许当数】。`,
|
||
},
|
||
// ★★★ 这一句是本函数最要紧的一句,见函数头。
|
||
emptyNote: out.length
|
||
? ''
|
||
: '★★【表在这一年没记事 ≠ 那一年没有事】。本表是【记事链】,它只记【变动】:' +
|
||
'那一年三公没换人,这一格就是空的 —— 而不是那一年天下太平。' +
|
||
'(景帝三年那一格里没有丞相,正因为陶青是前一年拜的,他那年没动。)' +
|
||
'⚠ 又:九卿栏本表只抠了两处,列将军栏表自己就阙。⇒ 空【不是结论】。',
|
||
withinYearNote:
|
||
'⚠ 表在很多格【不给月】,同一年两笔的先后【不可知】。' +
|
||
'★ events 的顺序是【本表的录入顺序】,不是发生顺序 —— 不许拿它排先后、不许画时间轴。',
|
||
othersNote: COVERAGE.jiuqing.note,
|
||
calendarNote: CALENDAR_NOTE.suiShou,
|
||
};
|
||
}
|
||
|
||
// ── 不变量自检:规矩写在注释里没用,写成断言才算数 ──
|
||
// (与 decisions.js 的 assertInvariants() 同性质。返回违规列表,空数组 = 通过。)
|
||
//
|
||
// ⚠ dynasties 参数:TABLE_SCOPE.dynastyIds 的核对要拿 DYNASTIES 才验得了,而本文件
|
||
// 【绝不 import dynasties.js】(它是纯常量表,无依赖,且另一条线正在改它)。
|
||
// ⇒ 由调用方把 DYNASTIES 递进来(services/court.js 递)。不给就跳过那一段 ——
|
||
// ⚠ 跳过【不是通过】:court.js 那边另有一条断言钉着这件事。
|
||
export function assertGongqingInvariants({ dynasties = null } = {}) {
|
||
const bad = [];
|
||
const seatIds = new Set(SEATS.map((s) => s.id));
|
||
const eraKeys = new Set(ALL_ERAS.map((e) => e.key));
|
||
|
||
// 纪年表自洽:count 必须与 from/to 对得上,且各段首尾相接、不重不漏
|
||
for (const r of RULERS) {
|
||
for (const e of r.eras) {
|
||
if (e.to - e.from + 1 !== e.count) bad.push(`${r.name} ${e.key}: count=${e.count} 与 from/to 不符`);
|
||
}
|
||
}
|
||
const spans = ALL_ERAS.slice().sort((a, b) => a.from - b.from);
|
||
for (let i = 1; i < spans.length; i++) {
|
||
if (spans[i].from !== spans[i - 1].to + 1) {
|
||
bad.push(`纪年不连续:${spans[i - 1].key}(到${spans[i - 1].to}) → ${spans[i].key}(从${spans[i].from})`);
|
||
}
|
||
}
|
||
|
||
let prevYear = -Infinity;
|
||
for (const e of GONGQING) {
|
||
const tag = `${e.era}/${e.office}/${e.name ?? '—'}/${e.event}`;
|
||
// courtAt 靠年份升序做重放,乱序会静默算错
|
||
if (e.year < prevYear) bad.push(`${tag}: GONGQING 必须按年升序 —— courtAt 靠它重放`);
|
||
prevYear = e.year;
|
||
|
||
if (!Number.isInteger(e.year)) bad.push(`${tag}: year 必须是整数(负 = 公元前)`);
|
||
if (!e.era || !e.eraRaw) bad.push(`${tag}: era / eraRaw 都得有 —— 补全的和原文的分开放`);
|
||
if (!EVENT_WORDS.has(e.event)) bad.push(`${tag}: event「${e.event}」不在 EVENTS 里 —— 只许用表自己的字`);
|
||
if (!e.quote) bad.push(`${tag}: 缺 quote —— 正文是推演,注是原文,没有原文就不许有这条`);
|
||
if (e.source !== BIAO) bad.push(`${tag}: source 必须是本卷;旁证请放 corroboration`);
|
||
if (e.seat && !seatIds.has(e.seat)) bad.push(`${tag}: 未知 seat「${e.seat}」`);
|
||
if (e.seat && SEAT_BY_OFFICE[e.office] !== e.seat) {
|
||
bad.push(`${tag}: office「${e.office}」与 seat「${e.seat}」对不上(见 SEATS)`);
|
||
}
|
||
// ★ 反过来也得管:三公的官【漏了 seat】会被 courtAt 扔进 others,
|
||
// 于是 COVERAGE.sangong 声称的「全覆盖」就成了假话,而且【一声不响】。
|
||
if (!e.seat && SEAT_BY_OFFICE[e.office]) {
|
||
bad.push(
|
||
`${tag}: office「${e.office}」属于座次「${SEAT_BY_OFFICE[e.office]}」却没标 seat —— ` +
|
||
'courtAt 会把它扔进 others,三公的「全覆盖」当场变成假话'
|
||
);
|
||
}
|
||
|
||
// ★ 引文里【一个字的顏師古注都不许有】—— 他是唐人,班固是东汉人
|
||
for (const w of ['師古曰', '應劭曰', '如淳曰', '晉灼曰', '臣瓚曰', '張晏曰', '文穎曰']) {
|
||
if (String(e.quote).includes(w)) bad.push(`${tag}: quote 里混进了后人注「${w}」—— 必须剔`);
|
||
}
|
||
// ★ 年份不许从「N年」算出来:凡 quote 里带「N年遷/免/卒…」的,本表都只照录
|
||
if (/[一二三四五六七八九十]+年(遷|免|卒|薨|死|徙|貶|賜告|老病免|病免|有罪自殺)/.test(e.quote) && !e.caveat) {
|
||
bad.push(`${tag}: quote 带「若干年」记法却没有 caveat 说明「照录不计算」—— 见卷首第二条`);
|
||
}
|
||
// ★★ 姓名不具就必须是 null,不许猜 —— 但【由记事链解出来的不算猜】。
|
||
// 本表的行文惯例:头回出现给全名(「魏其侯竇嬰為丞相」),此后只用名(「丞相嬰免」)。
|
||
// → 一个单字名要能给 person,必须在【本表之前的某一笔】里,同一个 person 出过全名。
|
||
// 解得出 = 有据;解不出 = 猜。这条差别不能靠自觉,得算出来。(先写测试才逼出来的:
|
||
// 原先一刀切禁掉单字名 + person,把「丞相嘉薨」= 申屠嘉这种【有据的】也误伤了。)
|
||
if (e.name && [...e.name].length === 1 && e.person) {
|
||
const introduced = GONGQING.some(
|
||
(x) => x.year <= e.year && x.person === e.person && [...(x.name || '')].length > 1
|
||
);
|
||
if (!introduced) {
|
||
bad.push(
|
||
`${tag}: 单字人名「${e.name}」给了 person「${e.person}」,` +
|
||
'可本表【在此之前没有任何一笔给过他全名】—— 那就是猜的(见 PERSON_NOTE / SHIGU_NOTE)'
|
||
);
|
||
}
|
||
}
|
||
// ★ 两个见证打架的,不许硬给结论
|
||
if (e.variantUnresolved && !e.caveat) bad.push(`${tag}: 有 variantUnresolved 却没 caveat`);
|
||
// ★ 推断出来的年份必须标出来
|
||
if (e.yearInferred && !/推断|推算/.test(e.caveat || '')) {
|
||
bad.push(`${tag}: yearInferred=true 却没在 caveat 里说清楚这是推断`);
|
||
}
|
||
// ★ 只有一个见证的必须说
|
||
if (e.witnesses !== 2 && !e.caveat) bad.push(`${tag}: witnesses=${e.witnesses} 却没有 caveat 交代`);
|
||
}
|
||
|
||
// 覆盖范围不许自吹:三公说全覆盖,就不许有落在范围外的三公条目冒充
|
||
for (const e of GONGQING) {
|
||
const inRange = e.year >= COVERAGE.years.from && e.year <= COVERAGE.years.to;
|
||
if (!inRange && !e.seed) bad.push(`${e.era}/${e.office}: 落在覆盖范围外却没标 seed`);
|
||
}
|
||
return bad;
|
||
}
|
||
|
||
export { ALL_ERAS, SEAT_BY_OFFICE, TERMINAL_WORDS };
|