kairos-chain 3.58.2 → 3.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +171 -0
  3. data/lib/kairos_mcp/version.rb +1 -1
  4. data/templates/knowledge/project_orientation_report/assets/report_template.html +214 -0
  5. data/templates/knowledge/project_orientation_report/project_orientation_report.md +257 -0
  6. data/templates/knowledge/project_orientation_report/references/worked_example.md +106 -0
  7. data/templates/knowledge/project_orientation_report/scripts/check_report.py +658 -0
  8. data/templates/knowledge/project_orientation_report/test/fixtures/bad_all_exempt.html +31 -0
  9. data/templates/knowledge/project_orientation_report/test/fixtures/bad_comment_details.html +34 -0
  10. data/templates/knowledge/project_orientation_report/test/fixtures/bad_details_open.html +34 -0
  11. data/templates/knowledge/project_orientation_report/test/fixtures/bad_dot_svg.html +31 -0
  12. data/templates/knowledge/project_orientation_report/test/fixtures/bad_em_font_size.html +31 -0
  13. data/templates/knowledge/project_orientation_report/test/fixtures/bad_empty_visuals.html +31 -0
  14. data/templates/knowledge/project_orientation_report/test/fixtures/bad_hidden_headings.html +1 -0
  15. data/templates/knowledge/project_orientation_report/test/fixtures/bad_missing_section.html +28 -0
  16. data/templates/knowledge/project_orientation_report/test/fixtures/bad_placeholder.html +31 -0
  17. data/templates/knowledge/project_orientation_report/test/fixtures/bad_stylesheet_pre.html +33 -0
  18. data/templates/knowledge/project_orientation_report/test/fixtures/bad_summary_content.html +32 -0
  19. data/templates/knowledge/project_orientation_report/test/fixtures/bad_svg_overflow_rect.html +31 -0
  20. data/templates/knowledge/project_orientation_report/test/fixtures/bad_svg_smuggle.html +31 -0
  21. data/templates/knowledge/project_orientation_report/test/fixtures/bad_svg_transform.html +31 -0
  22. data/templates/knowledge/project_orientation_report/test/fixtures/bad_token_forms.html +31 -0
  23. data/templates/knowledge/project_orientation_report/test/fixtures/bad_too_long.html +31 -0
  24. data/templates/knowledge/project_orientation_report/test/fixtures/bad_translate_one_arg.html +31 -0
  25. data/templates/knowledge/project_orientation_report/test/fixtures/bad_whitespace_pre.html +34 -0
  26. data/templates/knowledge/project_orientation_report/test/fixtures/good_declared_tokens.html +32 -0
  27. data/templates/knowledge/project_orientation_report/test/fixtures/good_minimal.html +31 -0
  28. data/templates/knowledge/project_orientation_report/test/fixtures/good_nine_sections.html +34 -0
  29. data/templates/knowledge/project_orientation_report/test/fixtures/good_tspan.html +31 -0
  30. data/templates/knowledge/project_orientation_report/test/test_check_report.py +136 -0
  31. data/templates/skillsets/account_manager/config/accounts.yml +115 -0
  32. data/templates/skillsets/account_manager/knowledge/account_manager_guide/account_manager_guide.md +200 -0
  33. data/templates/skillsets/account_manager/lib/account_manager/config.rb +259 -0
  34. data/templates/skillsets/account_manager/lib/account_manager/importer.rb +122 -0
  35. data/templates/skillsets/account_manager/lib/account_manager/money.rb +64 -0
  36. data/templates/skillsets/account_manager/lib/account_manager/report.rb +247 -0
  37. data/templates/skillsets/account_manager/lib/account_manager/store.rb +718 -0
  38. data/templates/skillsets/account_manager/lib/account_manager/tool_helpers.rb +54 -0
  39. data/templates/skillsets/account_manager/lib/account_manager.rb +30 -0
  40. data/templates/skillsets/account_manager/plugin/SKILL.md +96 -0
  41. data/templates/skillsets/account_manager/plugin/agents/bookkeeper.md +81 -0
  42. data/templates/skillsets/account_manager/skillset.json +33 -0
  43. data/templates/skillsets/account_manager/test/test_account_manager.rb +1319 -0
  44. data/templates/skillsets/account_manager/tools/am_close.rb +80 -0
  45. data/templates/skillsets/account_manager/tools/am_entry.rb +144 -0
  46. data/templates/skillsets/account_manager/tools/am_import.rb +70 -0
  47. data/templates/skillsets/account_manager/tools/am_query.rb +96 -0
  48. data/templates/skillsets/account_manager/tools/am_receipt.rb +69 -0
  49. data/templates/skillsets/account_manager/tools/am_report.rb +85 -0
  50. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/consensus.rb +65 -5
  51. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/prompt_builder.rb +35 -1
  52. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/review_serializer.rb +101 -2
  53. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/sanitizer.rb +137 -8
  54. data/templates/skillsets/multi_llm_review/skillset.json +2 -2
  55. data/templates/skillsets/multi_llm_review/test/test_evidence_fidelity.rb +484 -0
  56. data/templates/skillsets/multi_llm_review/tools/multi_llm_review.rb +52 -5
  57. data/templates/skillsets/multi_llm_review/tools/multi_llm_review_collect.rb +81 -11
  58. data/templates/skillsets/project_manager/config/pm.yml +3 -1
  59. data/templates/skillsets/project_manager/lib/project_manager/digest.rb +77 -11
  60. data/templates/skillsets/project_manager/lib/project_manager/parsed_time.rb +77 -0
  61. data/templates/skillsets/project_manager/lib/project_manager/store.rb +23 -5
  62. data/templates/skillsets/project_manager/lib/project_manager.rb +1 -0
  63. data/templates/skillsets/project_manager/plugin/SKILL.md +13 -5
  64. data/templates/skillsets/project_manager/plugin/agents/secretary.md +54 -23
  65. data/templates/skillsets/project_manager/skillset.json +1 -1
  66. data/templates/skillsets/project_manager/test/test_project_manager.rb +460 -3
  67. data/templates/skillsets/project_manager/tools/pm_digest.rb +13 -1
  68. metadata +49 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 354e0a87d4c0ed3736972c2fde97cf1537b4054d6ab86ae3cdf593e2c6d08a76
4
- data.tar.gz: 64237a0328caa2330bbebd4e188c017fc076bc773a9e0a4bcf05ea3fe8e9b118
3
+ metadata.gz: d38191ff3e513822d6183bf4fee4c92e497148978eda3bda064a01b81d0bf95b
4
+ data.tar.gz: 97999aa9377a086ea092237ad53605fec24b9e01c9691e7c92c24b6329bd565e
5
5
  SHA512:
6
- metadata.gz: bde4d816b2a7610de034633ae467c1f6febda1b907b81fb156b356b5d86980f57c37c3e8903cdeb24a861323d16705a1d167e63390d9c1350d8bb880fb52f3da
7
- data.tar.gz: 9e32311add613a1bbddffa704f0720622ca436be7a0bfc56b237d3ac650cf574cdb82ed3f12550e94782020c1b4c762baa6333db8b72a1ea04f32bf46a37cc8e
6
+ metadata.gz: eacfebd73445ea5e6a503bb34e8978a0a6c649d34a46810140a885f235e3933b01701d45921341b6771caa64c58f4dac61f51233d2741417e8b59be111196109
7
+ data.tar.gz: bffb450e4de67e1b3c179de5bd48b86d1d6d3c2bc8e69cd6878fd6d89b6e3346fae29b09cd5ef79ddbb12f16498e0f944da84af4a62b3a36eff0db05ea5b6d96
data/CHANGELOG.md CHANGED
@@ -4,6 +4,177 @@ All notable changes to the `kairos-chain` gem will be documented in this file.
4
4
 
5
5
  This project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [3.61.0] - 2026-08-06
8
+
9
+ ### Fixed
10
+
11
+ - **`multi_llm_review` (SkillSet 0.9.0) — a finding reaches the record whole, and the record
12
+ stops claiming what it cannot know.** A downstream instance measured, across four real rounds,
13
+ that 18 of 21 aggregated findings came back at exactly 201 bytes while `reviews[].raw_text` was
14
+ empty on every row and `raw_text_length` reported the real size. Three bounds were doing it: an
15
+ inclusive Range (`issue.strip[0..200]`, hence 201) in aggregation, the 500-character display
16
+ limit applied to the record as well as the prompt, and a serializer row that carried a reply's
17
+ length but never the reply. A fourth defect discarded a distinct finding on dedup collision
18
+ without saying so.
19
+
20
+ Findings are now bounded in **bytes** at `FINDING_RECORD_MAX_LEN = 8000` for the record, with
21
+ `DEFAULT_MAX_LEN = 500` still applied by every path taking a finding into a prompt. The dedup key
22
+ is unchanged at 80 characters — widening it would stop two reviewers describing one defect from
23
+ merging, which moves the finding count and the convergence denominator — but the surviving text
24
+ is no longer arbitrary: `issue` comes from a member whose severity equals the merged severity,
25
+ and distinct texts survive in `issue_variants` (capped at `MAX_ISSUE_VARIANTS = 8`, with
26
+ `issue_variants_omitted` naming what the cap dropped). Every row now carries `raw_text_excerpt`
27
+ unconditionally at 4096 bytes, and the reply itself in `raw_text` on request
28
+ (`include_raw_text`, 65536 bytes). Findings carried into a later round's prompt are sanitised and
29
+ folded to one line — a path that previously took reviewer text into a prompt with no sanitisation
30
+ at all.
31
+
32
+ **The two evidence fields are sanitised transcriptions, not verbatim records, and the tool
33
+ schemas now say so** rather than implying otherwise. The text is byte-clamped, NFKC-normalised,
34
+ stripped of invisible characters, tag-escaped, then byte-clamped again; normalisation rewrites
35
+ compatibility forms, the strip removes five of Unicode's eight mandatory line breaks, and the tag
36
+ escape collapses unbounded whitespace. No field states whether a stored text is the whole reply.
37
+ A completeness flag was implemented for exactly that purpose and then removed: three reviewers
38
+ measured it wrong in **both** directions — a 4,010-byte reply stored as 18 bytes reported
39
+ complete, and a reply whose every readable byte survived reported truncated. "Was anything
40
+ dropped" cannot be answered by byte counts taken around a pass that also rewrites, strips and
41
+ escapes. On delegated runs the pending-state record keeps each subprocess reply as it arrived; on
42
+ single-phase runs the returned payload is the only form there is, and the schema distinguishes
43
+ the two.
44
+
45
+ Six review rounds, four pre-flight falsifier passes and forty-plus mutations. Every defect in
46
+ this change was found by adversarial reading or by mutating the code in a copy outside the
47
+ repository; **none** by the test suite passing. Known and disclosed rather than closed: the
48
+ excerpt can store a word the reviewer did not write (normalisation cannot simply be dropped —
49
+ the delimiter pattern matches ASCII angle brackets, so a fullwidth `<artifact>` would pass
50
+ straight through an escape that no longer normalises, and the escape-without-normalise entry
51
+ point `stated_text` has been waiting on since R2 does not exist yet); the measured response
52
+ ceiling of 28.9 MB against a declared 14.4 MB; and thirteen sites that survive deletion with the
53
+ suite green.
54
+
55
+ ## [3.60.0] - 2026-08-05
56
+
57
+ ### Added
58
+
59
+ - **`account_manager` (SkillSet 0.1.0) — a jurisdiction-neutral double-entry ledger for a
60
+ one-person business that is also a household cash book.** One person, two purses: the books must
61
+ separate for tax, but the money does not — the owner draws from the business and pays business
62
+ costs from a private card. Six tools (`am_entry`, `am_import`, `am_query`, `am_report`,
63
+ `am_receipt`, `am_close`), one ledger with two books, one currency, and a bookkeeper-persona
64
+ sub-agent that transcribes on the way in and reads figures on the way out but cannot post,
65
+ confirm, discard, close or bind evidence.
66
+
67
+ No country's rules appear in any code path. The chart of accounts, tax labels, fiscal year and
68
+ import profiles are configuration; adding a country means writing one YAML file. The loader has
69
+ one refusal with a closed list of causes, and a missing ledger configuration is refused rather
70
+ than substituted by the shipped example.
71
+
72
+ Three things carry the design. A **range** is one calendar month derived from the transaction
73
+ date, so ranges cannot overlap or leave a gap and the rules that would have policed that do not
74
+ exist. A **proposal** is not a figure: imported rows and transcriptions are visible, counted by
75
+ no report, and become postings only by an explicit operator call. The **annual close posts, then
76
+ seals** — it credits each book's own retained earnings dated the fiscal year's last day, then
77
+ seals every month of that year, and that entry is the one posting permitted into a
78
+ period-closed (never sealed) range, because refusing it would make the annual close unreachable
79
+ in ordinary month-by-month use.
80
+
81
+ Design review did not converge over three rounds, so the design was implemented rather than
82
+ argued further; two implementation review rounds followed. Round 1 found a ledger that lost
83
+ records — an acknowledged posting absent from disk, because each tool cached its own store and
84
+ saved a stale snapshot over it — plus a refusal idiom that never executed
85
+ (`def m(id) = h[id] or raise X` parses as `(def …) or raise`), a closing entry that credited the
86
+ wrong book, and a year sealed as year zero from `'abc'.to_i`. Twenty-seven of its twenty-eight
87
+ blocking findings are fixed, and three independent reviewers verified the fixes in round 2.
88
+ Round 2's own findings are recorded and open: twelve are missing test coverage rather than
89
+ defects, and the remainder sit at configuration edges. Known and unfixed: there is no locking,
90
+ so the store is safe for one operator on one machine and not beyond it.
91
+
92
+ Not auto-installed — `account_manager` is not in `CORE_SKILLSETS`, so it ships in the gem and is
93
+ installed explicitly, like `project_manager`.
94
+
95
+ ## [3.59.0] - 2026-08-05
96
+
97
+ ### Added
98
+
99
+ - **`project_manager` names what no bucket covered (SkillSet 0.3.0).** `pm_digest`
100
+ sorted open items into four buckets and reported the remainder as a count called
101
+ `healthy_count`. Dormancy is computed at high salience only, so a normal- or
102
+ low-salience item with no deadline was counted but never named, however long it
103
+ sat. On the operator's own store that was 12 of 22 open items, the oldest
104
+ untouched for 98 days, and nothing in the digest would ever have raised them.
105
+
106
+ The digest now returns `uncovered_count` and `uncovered_stale`. The latter names
107
+ every uncovered item the store already calls dormant, in full and oldest first,
108
+ ties broken by id — in full rather than a top-N because untouched items advance
109
+ in lockstep, so a fixed cut omits the same work every day forever. The secretary
110
+ agent reads the list out after the buckets with no next step attached: it is a
111
+ list of what nothing raised, not a bucket to act on. `healthy_count` survives as
112
+ a deprecated alias, because the name is wrong — the number mixes work that is
113
+ fine with work nobody is watching. Bucket membership is otherwise unchanged.
114
+
115
+ Hardening found while reviewing it, all reachable through the tool surface.
116
+ `pm_item` writes `due` and `touched_at` through with no validation and every
117
+ reader assumed `Time.parse` would succeed, so one bad value replaced the whole
118
+ digest — or the whole deadline query — with an error object. Both now read
119
+ through `ProjectManager.parse_time`, which answers nil for a malformed string, a
120
+ non-string and an out-of-range field alike. The same discipline covers
121
+ caller-supplied numbers in `whole_number`, including the `pm.yml` thresholds and
122
+ the `digest:` mapping they sit in, so an operator typo in the one file
123
+ `skillset upgrade` never repairs falls back to defaults instead of disabling the
124
+ digest. `summarize` also carries the raw `touched_at` now, so a consumer can tell
125
+ a missing marker from an unreadable one — the secretary is required to word them
126
+ differently and previously had to guess.
127
+
128
+ Eight review rounds against a frozen target, closed by exhaustion rather than by
129
+ threshold: the last round's findings were pre-existing SkillSet defects outside
130
+ the target, not defects in this change. The recurring mistake worth recording is
131
+ that seven consecutive rounds each found the same shape — a guard placed one step
132
+ short of where the value enters — at the call site instead of the source, at two
133
+ of three exception classes, at a config hash's values instead of the hash, and at
134
+ the hash instead of the read that produces it.
135
+
136
+ - **`project_orientation_report` L1 knowledge.** A fixed procedure for producing a
137
+ one-page HTML report that explains where a single thread of work stands, written
138
+ for a reader who has not followed it. Ten invariants, a fixed eight-section order,
139
+ three collapsed appendices, and SVG rules; the checkable part is enforced by
140
+ `scripts/check_report.py` (standard library only, exit 0 on pass).
141
+
142
+ The two invariants that carry the most weight are non-obvious. The writer must
143
+ not hold the session context that produced the work — a writer who knows
144
+ everything skips premises without noticing, so the report is written by a
145
+ context-blank process given only the artifacts. And a section that explains a
146
+ *change* must carry one worked example from start to finish, because a reader
147
+ forced to re-learn the setup at every section stops following at the first switch.
148
+
149
+ The design was not validated by a design review. It was validated by building
150
+ four prototypes on the same subject and having a human read each one: invariants
151
+ 7, 8, 9, 10 and the SVG rules all came out of those judgments and none of them
152
+ came out of the design table. `references/worked_example.md` records which
153
+ prototype failed how.
154
+
155
+ The checker itself went through two rounds of multi-LLM review, neither of which
156
+ approved it, and the shape of what they found is why it ships as it does. The
157
+ first version matched tags with regular expressions, so every content check was
158
+ defeated by moving content into a region the pattern did not scan — wrapping the
159
+ failing example in `<details open>` turned it into a pass. It now builds a
160
+ document tree and measures rendered text, so relocating content no longer helps.
161
+ The second round found a further class: a report could declare every section
162
+ exempt and pass as a blank page, a one-argument `translate` silently moved
163
+ nothing, and a relative font unit was read as a tiny absolute size. Those are
164
+ closed, and each is now a fixture.
165
+
166
+ What is deliberately not closed is stated in the script and in the skill: this
167
+ is a lint over the ways an author gets a wrong answer while writing normally,
168
+ not a boundary against someone determined to pass an unreadable report. Text
169
+ drawn by a stylesheet, an `<iframe srcdoc>`, or a full-width spelling of a
170
+ forbidden label all get through, and closing that class needs a renderer rather
171
+ than a parser. A pass means a handful of known ways of being unreadable are
172
+ absent; whether the report can actually be understood in one pass stays a human
173
+ judgement. `test/` ships 22 fixtures and a runner so the boundary is checkable
174
+ rather than asserted — 18 that must fail, each naming the check that must catch
175
+ it, and 4 that must pass, because closing an evasion is trivial if the gate is
176
+ allowed to reject everything.
177
+
7
178
  ## [3.58.2] - 2026-08-03
8
179
 
9
180
  ### Fixed
@@ -1,4 +1,4 @@
1
1
  module KairosMcp
2
- VERSION = "3.58.2"
2
+ VERSION = "3.61.0"
3
3
  CHANGELOG_URL = "https://github.com/masaomi/KairosChain_2026/blob/main/CHANGELOG.md"
4
4
  end
@@ -0,0 +1,214 @@
1
+ <!DOCTYPE html>
2
+ <html lang="ja">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <!-- Tokens that LOOK work-internal but are ordinary vocabulary (A4, Q3, gpt-5).
7
+ Declaring one is a decision; leaving this empty is the default. -->
8
+ <meta name="orientation-allowed-tokens" content="">
9
+ <title>作業名 — 現状レポート</title>
10
+ <style>
11
+ :root {
12
+ --ink: #23262b;
13
+ --muted: #5f6672;
14
+ --line: #d5d9e0;
15
+ --panel: #f7f8fa;
16
+ --accent: #b3402f;
17
+ }
18
+ body {
19
+ font-family: "Hiragino Sans", "Noto Sans JP", "Yu Gothic", ui-sans-serif, sans-serif;
20
+ color: var(--ink);
21
+ background: #fff;
22
+ line-height: 1.9;
23
+ font-size: 16.5px;
24
+ max-width: 46rem;
25
+ margin: 0 auto;
26
+ padding: 2.5rem 1.2rem 5rem;
27
+ }
28
+ h1 { font-size: 1.5rem; line-height: 1.5; margin: 0 0 .4rem; }
29
+ h2 {
30
+ font-size: 1.13rem;
31
+ margin: 3rem 0 .9rem;
32
+ padding-bottom: .35rem;
33
+ border-bottom: 2px solid var(--line);
34
+ }
35
+ p { margin: .9rem 0; }
36
+ .stamp {
37
+ background: var(--panel);
38
+ border: 1px solid var(--line);
39
+ border-radius: 6px;
40
+ padding: .8rem 1rem;
41
+ font-size: .87rem;
42
+ color: var(--muted);
43
+ line-height: 1.8;
44
+ }
45
+ .stamp b { color: var(--ink); font-weight: 600; }
46
+ table { border-collapse: collapse; width: 100%; margin: 1.2rem 0; font-size: .93rem; }
47
+ th, td { border: 1px solid var(--line); padding: .5rem .7rem; text-align: left; vertical-align: top; }
48
+ th { background: var(--panel); font-weight: 600; }
49
+ figure { margin: 1.4rem 0; }
50
+ figcaption { font-size: .85rem; color: var(--muted); margin-top: .5rem; }
51
+ svg { display: block; margin: 0 auto; }
52
+ .mark { color: var(--accent); font-weight: 600; }
53
+ details {
54
+ margin-top: 3rem;
55
+ border-top: 1px solid var(--line);
56
+ padding-top: 1rem;
57
+ }
58
+ summary { cursor: pointer; font-weight: 600; }
59
+ @media print {
60
+ body { max-width: none; font-size: 11pt; }
61
+ details { page-break-before: always; }
62
+ details[open] summary { list-style: none; }
63
+ }
64
+ </style>
65
+ </head>
66
+ <body>
67
+
68
+ <!-- 節0 表紙。条件2 — 時点を名指しする。図表は不要、時点の枠がその代わり。
69
+ data-visual="none" が「この節に図表が無いのは意図的だ」という宣言。
70
+ 宣言の無い節は図表を要求される -->
71
+ <h1 data-visual="none">《作業名》 — 現状レポート</h1>
72
+ <p>《この 1 枚は何の話か。1 文で》</p>
73
+ <div class="stamp">
74
+ <b>生成</b> 《YYYY-MM-DD HH:MM》 /
75
+ <b>git</b> 《short commit》 /
76
+ <b>chain の高さ</b> 《length》<br>
77
+ <b>読んだ入力</b> 《n 件。一覧は付録 C》
78
+ </div>
79
+
80
+ <!-- 節1 登場人物。作業の内部ではなく、作業に入る前の前提だけ。SVG 必須 -->
81
+ <h2>登場人物</h2>
82
+ <p>《誰が誰に何を渡すのか。ここでは仕組みを書かない》</p>
83
+ <figure>
84
+ <!--
85
+ 箱の幅の決め方。SVG の text は折り返さないので、書き手が計算する。
86
+
87
+ 日本語 1 文字 ≈ font-size × 1.0 半角英数 1 文字 ≈ font-size × 0.55
88
+
89
+ font-size 14 なら日本語 1 文字が 14px。下の箱は幅 220px なので **15 文字**まで。
90
+ 超えるときは、箱を広げるか、下のように <tspan> で行を分ける。
91
+ 1 行に収める必要はない。収まらない行を 1 本の text に押し込むのが失敗の形。
92
+ 検収スクリプトは、各行を親の <rect> と照合して溢れを落とす。
93
+ -->
94
+ <svg viewBox="0 0 760 210" style="width:100%;max-width:760px;height:auto" role="img">
95
+ <title>《図の内容を 1 文で。読み上げ用》</title>
96
+ <defs>
97
+ <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5"
98
+ markerWidth="7" markerHeight="7" orient="auto-start-reverse">
99
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="#5f6672"/>
100
+ </marker>
101
+ </defs>
102
+ <rect x="10" y="60" width="220" height="76" rx="6" fill="#f7f8fa" stroke="#5f6672"/>
103
+ <text font-size="14" text-anchor="middle"
104
+ font-family="Hiragino Sans, Noto Sans JP, sans-serif" fill="#23262b">
105
+ <tspan x="120" y="94">《登場人物 1 の名前》</tspan>
106
+ <tspan x="120" y="116">《長ければ 2 行目へ》</tspan>
107
+ </text>
108
+ <rect x="270" y="60" width="220" height="76" rx="6" fill="#f7f8fa" stroke="#5f6672"/>
109
+ <text font-size="14" text-anchor="middle"
110
+ font-family="Hiragino Sans, Noto Sans JP, sans-serif" fill="#23262b">
111
+ <tspan x="380" y="94">《登場人物 2 の名前》</tspan>
112
+ <tspan x="380" y="116">《長ければ 2 行目へ》</tspan>
113
+ </text>
114
+ <rect x="530" y="60" width="220" height="76" rx="6" fill="#f7f8fa" stroke="#5f6672"/>
115
+ <text font-size="14" text-anchor="middle"
116
+ font-family="Hiragino Sans, Noto Sans JP, sans-serif" fill="#23262b">
117
+ <tspan x="640" y="94">《登場人物 3 の名前》</tspan>
118
+ <tspan x="640" y="116">《長ければ 2 行目へ》</tspan>
119
+ </text>
120
+ <line x1="230" y1="98" x2="265" y2="98" stroke="#5f6672" marker-end="url(#arrow)"/>
121
+ <line x1="490" y1="98" x2="525" y2="98" stroke="#5f6672" marker-end="url(#arrow)"/>
122
+ <text x="248" y="46" text-anchor="middle" font-size="11"
123
+ font-family="Hiragino Sans, Noto Sans JP, sans-serif" fill="#5f6672">《渡すもの》</text>
124
+ <text x="508" y="46" text-anchor="middle" font-size="11"
125
+ font-family="Hiragino Sans, Noto Sans JP, sans-serif" fill="#5f6672">《渡すもの》</text>
126
+ </svg>
127
+ <figcaption>《図の説明。1 行》</figcaption>
128
+ </figure>
129
+
130
+ <!-- 節2 何が壊れていたか。条件8 — 実際の入力と出力の値を 1 組 -->
131
+ <h2>何が壊れていたか</h2>
132
+ <p>《具体的に何が起きたのか》</p>
133
+ <table>
134
+ <tr><th>入力</th><th>出た結果</th></tr>
135
+ <tr><td>《実際に与えた値》</td><td>《実際に返った値》</td></tr>
136
+ </table>
137
+
138
+ <!-- 節3 直そうとして何が起きたか。条件10 — 追う例を決め、時点ごとの扱いを 1 枚の表に -->
139
+ <h2>直そうとして何が起きたか</h2>
140
+ <p>《経緯を 1 本の線で。以下は追いかける例》</p>
141
+ <table>
142
+ <tr><th>時点</th><th>《追う例 その 1》</th><th>《追う例 その 2》</th></tr>
143
+ <tr><td>《最初》</td><td>《どうなったか》</td><td>《どうなったか》</td></tr>
144
+ <tr><td>《修正 1》</td><td>《どうなったか》</td><td><span class="mark">《ここで開いた穴》</span></td></tr>
145
+ <tr><td>《最終》</td><td>《どうなったか》</td><td>《どうなったか》</td></tr>
146
+ </table>
147
+
148
+ <!-- 節4 どう閉じたか。条件10 — 節3 と同じ例で、前と後を対比する -->
149
+ <h2>どう閉じたか</h2>
150
+ <p>《最後にとった手と、その一言の理由》</p>
151
+ <figure>
152
+ <svg viewBox="0 0 700 220" style="width:100%;max-width:700px;height:auto" role="img">
153
+ <title>《前と後で、追っている例の扱いがどう変わったか》</title>
154
+ <rect x="20" y="20" width="320" height="180" rx="6" fill="#f7f8fa" stroke="#5f6672"/>
155
+ <text x="40" y="50" font-size="13"
156
+ font-family="Hiragino Sans, Noto Sans JP, sans-serif" fill="#23262b">《修正前》</text>
157
+ <text x="40" y="100" font-size="12"
158
+ font-family="Hiragino Sans, Noto Sans JP, sans-serif" fill="#23262b">《追う例 その 1 の扱い》</text>
159
+ <text x="40" y="130" font-size="12"
160
+ font-family="Hiragino Sans, Noto Sans JP, sans-serif" fill="#b3402f">《追う例 その 2 の扱い》</text>
161
+ <rect x="360" y="20" width="320" height="180" rx="6" fill="#f7f8fa" stroke="#5f6672"/>
162
+ <text x="380" y="50" font-size="13"
163
+ font-family="Hiragino Sans, Noto Sans JP, sans-serif" fill="#23262b">《修正後》</text>
164
+ <text x="380" y="100" font-size="12"
165
+ font-family="Hiragino Sans, Noto Sans JP, sans-serif" fill="#23262b">《追う例 その 1 の扱い》</text>
166
+ <text x="380" y="130" font-size="12"
167
+ font-family="Hiragino Sans, Noto Sans JP, sans-serif" fill="#23262b">《追う例 その 2 の扱い》</text>
168
+ </svg>
169
+ <figcaption>《なぜこれで閉じるのか。1 行》</figcaption>
170
+ </figure>
171
+
172
+ <!-- 節5 今どこ。数字は必ず分母つき -->
173
+ <h2>今どこ</h2>
174
+ <table>
175
+ <tr><th>項目</th><th>状態</th></tr>
176
+ <tr><td>《進んだところ》</td><td>《数字は分母つきで》</td></tr>
177
+ <tr><td>《止まっているところ》</td><td>《何待ちか》</td></tr>
178
+ </table>
179
+
180
+ <!-- 節6 決まっていないこと。条件6 — 作業側が未決と書き残したものだけ。提案を書かない -->
181
+ <h2 data-visual="none">決まっていないこと</h2>
182
+ <ul>
183
+ <li>《作業側が未決と書き残していること》</li>
184
+ </ul>
185
+
186
+ <!-- 節7 記録の食い違い。条件5 — どれかに寄せない。無ければ「食い違いなし」と明記 -->
187
+ <h2>記録の食い違い</h2>
188
+ <table>
189
+ <tr><th>記録が言っていること</th><th>実際</th></tr>
190
+ <tr><td>《どの記録が何と書いているか》</td><td>《確かめた結果》</td></tr>
191
+ </table>
192
+
193
+ <details>
194
+ <summary>付録 A — 符牒の対応表</summary>
195
+ <table>
196
+ <tr><th>元の記録の符牒</th><th>本体での呼び名</th></tr>
197
+ <tr><td>《符牒》</td><td>《日本語の呼び名》</td></tr>
198
+ </table>
199
+ </details>
200
+
201
+ <details>
202
+ <summary>付録 B — 網羅の記録</summary>
203
+ <p>《変更ファイル一覧、テストの内訳、実測値の全部。引き継ぎ用》</p>
204
+ </details>
205
+
206
+ <details>
207
+ <summary>付録 C — 読んだもの</summary>
208
+ <ul>
209
+ <li><code>《パス》</code> — 《そこから取った内容を一言》</li>
210
+ </ul>
211
+ </details>
212
+
213
+ </body>
214
+ </html>