Appearance
Session handoff
Overwritten each session — this is state-of-now, not history. The journal is history. The next agent reads this before anything but ./init.sh.
Written: 2026-09-20 (last pass: stage 1 prototype-feedback grill, session chem-assistant-8c)
Two sessions ran in this workspace today, concurrently, and a third pass closed the day. The sections above the rule are written by
chem-assistant-4b, which did the UI-alignment grill (ADR-0064..0066). A parallel session did the curation/API rulings (ADR-0057..0063) and committed most of the day's docs, including that session's ADRs. Where either describes the other's work it says so and does not vouch for it. A third pass then brought the documentation site back into line with the repository — its half is the section "This session — the documentation site" below, and it adds blockers 9 to 13 rather than renumbering anything above.
Where things stand
This session (chem-assistant-8c) ran stage 1 /grill-with-docs over a prototype-test report and committed its rulings at 5f4cf06. Everything below the next rule was written by earlier sessions on the same day and is unchanged; where it says "the day's rulings" it means ADR-0057..0075, not these.
Eight ADRs, D-154..D-168. A Handler and a Curator used the built application and the curator's workbench; the owner answered fourteen grill questions, one at a time. ADR-0076 (Home is six cards, an unbuilt route is absent), ADR-0077 (Chrome is three parts), ADR-0078 (type and motion tokens), ADR-0079 (one control vocabulary), ADR-0080 (the Curator's surfaces state what the server states), ADR-0081 (the original document over the network, never a gate), ADR-0082 (a published version is read from its own payload), ADR-0083 (the record tabs reference fields only).
Nothing is built. These are rulings. The next session implements them, and the work spans both application repositories — ADR-0080 and ADR-0081 need API routes (PAGE_ALREADY_VERIFIED, GET /v1/curation/snapshots, GET /v1/corpus/documents/:sdsId/original) before their surfaces can exist.
The grill rounds are not done. No Griller has seen ADR-0076..0083 — not a cross-model round, not even a fork. AGENTS.md requires one before a stage is called complete, so stage 1 is open. A true second model needs a second terminal: claude --model claude-opus-4-8, then ListAgents and SendMessage with the grill prompt and the eight ADR paths. This is the first thing the next session should do, before implementing anything, because a defect found now is a ruling reworded and a defect found later is code rewritten.
Two collisions were raised rather than implemented over. ADR-0030 and ADR-0008 both carry "this ruling may not be re-decided". ADR-0076 amends ADR-0030 rather than superseding it — a Status-line supersession would have obliged ADR-0030 to read Superseded by, killing D-63 and D-64 along with the part being changed — and ADR-0083 affirms ADR-0008 by keeping every emergency route above the tab bar. Do not "simplify" either into a supersession.
Stage 1 /grill-with-docs ran and is closed by owner ruling. Five decisions, from a seven-question owner grill over the frontend's first-run and boot surfaces:
- ADR-0064 — D-138 the Standing Statement is stated on first run by a blocking First Run Notice shown once per device, in front of the router rather than as a route; D-139 that surface's Escalation control is app-authored chrome which acknowledges First Run and routes, and renders no Curated Escalation text; D-140 First Run is judged by this browser's storage and every read or write failure errs toward stating the disclaimer again.
- ADR-0065 — D-141 the Boot Splash's content is a closed set.
- ADR-0066 — D-142 the design extract binds colour, spacing and surface treatment, nothing else.
CONTEXT.md gained Standing Statement, First Run and Chrome. The PRD gained Coverage rows D-138..D-142. All of it is committed and both gates are green.
The implementing code is built and committed at aa493d5 in the frontend: Boot/SplashScreen.vue, Boot/FirstRunNotice.vue, utils/FirstRun.ts, the @theme palette in assets/css/main.css, and the caveat-token conversions on the record, spill and first-aid surfaces. US-42 was unbuilt before this and is now attached to a surface; US-43 was already StandingStatement.vue.
The ping-pong is the half-finished part. Three rounds ran, sixteen defects, all resolved — but all three Grillers were Agent(subagent_type: "fork"), not a second model. Round 3 hit the AGENTS.md three-round cap with defects still landing; the owner ruled accept-and-close, and the override plus its cost is recorded in the journal. The cross-model round has not run.
Uncommitted working tree
?? sds/ (6.5 MB, untracked — present before this session, not written by it)sds/ holds curation working material — CURATION-STEPS.md, MANUAL-STEPS.md, a select-span walkthrough, a list/ and a scripts/. It was already untracked when the prototype-feedback grill session started and nothing in that session touched it. Do not sweep it and do not commit it blind: find out whose it is first. It is neither in .gitignore nor in the traceability chain, which means nothing currently states what it is for.
Clean in all three repositories, git status --short in each, after the documentation-site pass committed. app/chemical-safety-assistant-api is at acb425b and app/chemical-safety-assistant-frontend at e9c9f9c — do not advance either gitlink; they were moved deliberately at 76102e0 so that they point at the code today's rulings describe.
Gate status
All three, re-run on 2026-09-20 at the end of the documentation pass. Each is the gate's own exit code, not a grep of its output.
=== Verification Summary === === Verification Summary === === Verification Summary ===
COVERAGE: PASS LINT: PASS LINT: PASS
FIXTURE: PASS TYPECHECK: PASS TYPECHECK: PASS
ADRSTATUS: PASS TEST: PASS TEST: PASS
IDSTATUS: PASS SEAM4: PASS RESULT: PASS
STACKCLAIMS: PASS RESULT: PASS (app/…-api)
CORPUS: PASS (app/…-frontend) 777 tests, 23 files
RESULT: PASS 802 tests, 65 files
(workspace root) 26 Playwright cases
347 ids declaredAll three green. The root was red for part of today on ten COVERAGE problems; every one belonged to the parallel session's D-128..D-137 and was closed by its own Coverage rows, not by anything here.
Both application gates were red from 2026-09-13 until today, in both repositories, from one cause: two commits written against a workspace layout where the app repos are siblings of scripts/ rather than gitlinks under app/. ADR-0063 (D-137) ruled the layout and both are now green. No test encoded either failure, which is why seven days passed.
Blockers
Carried forward from 2026-09-08 and still open. The closed ones are not repeated — they are history and live in the journal and in git.
The Plant's SDS binder is not secured. ADR-0011 makes it the Corpus; ADR-0016 permits a proxy for pipeline work only — read its abuse warning. The needs study (D-31) needs the same site's staff. Answered by: the human.
The Study Area is not chosen and The Plant has not supplied its chemical list (D-79, D-80). Corpus size is scoped by area, so the list is the sizing artifact and the Corpus has no size until it exists. A much smaller ask than the binder — no document handover, answerable by a supervisor — and a better test of access than waiting on it. Answered by: the human.
Asked 2026-09-20, and the test came back empty. The three questions went out — which production area uses the proof chemical, that area's chemical list, and who owns the emergency procedure there. The reply answered from the project poster, saying so in its own first line, and the poster names no production area. Every chemical it listed is already recorded with a page citation: Acetone, IPA, Toluene and the proof chemical at
poster-v2.md:81(R-16), and the history screen's Hydrochloric Acid, Sodium Hydroxide and Xylene atposter-v2.md:90andsource-poster.md:197. Nothing was learned, and nothing was recorded as research — an uncited paraphrase of a scanned Thai poster is what ADR-0027 exists to refuse, and the same facts are already held with page numbers.What the attempt did establish is about access rather than about chemicals: the questions have not yet reached anyone who has stood on The Plant's floor. The reply declined to claim the three history-screen chemicals belong to the Study Area, which is the correct answer from that source and is why it is worth recording rather than dismissing. The next attempt has to reach a หัวหน้างาน or a จป. at the site; a recipient holding only project materials cannot produce an area name however the question is worded. Blocker 1 is the same dependency, and it is the one to push on.
The spend cap number is not set (D-77). ~$4.50 measured across the prototype at rates read 2026-09-08; one doubles on 2027-01-01. Reaching the cap disables the Query Intent tier and the app serves the Routing Floor — the same state as no signal, already tested. Answered by: the human.
Two Curation artifacts need a site authority, not a curator. The Curated Escalation (D-95) needs a named reviewer for The Plant's own evacuate-and-call procedure; the Escalation Trigger (D-70) needs someone who knows how Handlers phrase an emergency on that floor. Both are on the critical path for emergency flows and gated on the same access as the binder. Until signed, the app ships hotline 1669 alone (D-113) and
isShippableEscalationfails a build that restores the evacuate condition (D-114). Sizing note:.scratch/chemical-safety-assistant/once-per-corpus-sizing.md. Answered by: the human.Corpus size is the schedule. Half a day to a full day per document is a floor (D-58, D-59), unchanged by ADR-0034 — that ADR decides which documents, not what each costs.
The cross-model Griller round has not run.CLOSED 2026-09-20. Run on Fable 5.1 and Sonnet, each a cold subagent with a model override, neither a fork. It found six defects the three fork rounds had all missed, two of them first-order:EscalationPanelwas still writing rawred-*whilemain.cssclaimed the alarm tokens covered it, and D-139 asserted a false set relation between Chrome and Conversational Content. Fixed at7505003; ruled by ADR-0070 (D-146, D-147) because both remaining defects sat in Accepted ADRs. Correcting this file's earlier claim and the journal's: a second model was reachable all along.AGENTS.mdsays the Agent tool cannot pinclaude-opus-4-8— true — and that was over-read as "no second model is reachable".fableandsonnetare pinnable. The prescribed Griller model still has not been used; two different models have. The brief is reusable at.scratch/chemical-safety-assistant/griller-brief-2026-09-20.md.Spec text is owed for D-139..D-142.CLOSED 2026-09-20 by/to-spec, typed by the owner. US-66..US-72 added; §1, §4, §6 and §8 carry the prose; Seam 4 extended rather than joined, so seams stay at five. Two ping-pong rounds ran with cold cross-model reviewers (Fable 5.1, Sonnet), 11 defects raised and resolved. Two of those defects were checks that did not exist: the spec described a Seam 4 extension nobody had built, and claimed built-output assertions for D-141/D-142 that were nowhere in the repository. Both are now real —e2e/Seam4NoNetwork.spec.tshas two virgin-device cases, andsrc/tests/components/OnePalette.spec.tssweeps for a second palette. D-141's closed set is recorded as having no mechanical assertion rather than an implied one.The
claude-opus-4-8Griller has still not been used. Five review rounds ran: three forks, then Fable 5.1 and Sonnet. AGENTS.md namesclaude-opus-4-8as the Griller default. Two attempts at a terminal session for it exited without registering as peers. Not blocking — two genuinely different models have reviewed this work — but the prescribed one has not.
Added by the documentation-site pass. Each is stated as a hole rather than as a plan, because none of them has been decided and writing a plan here would read as though one had been.
- Nothing can correct a wrong Curated Explanation. There is no replace, no retire and no edit: authoring a term that already has an explanation is refused (ADR-0073, D-150). And because
term @uniquespans soft-deleted rows, a soft delete keeps the term's key, so the term can never be explained again. A curator who writes the wrong explanation for a term has no move inside the product. ADR-0073 states this as the cost of refusing a silent overwrite and does not close it. - All sixteen Thai Section Headings are unsourced. GHS Annex 4 fixes the English; the Thai wording comes from a Thai ministerial notification that no artifact in this workspace names. They ship on a surface a Handler reads. A
/researchpass against the primary source would close it; it is model-invocable, so an agent may run it. - The five remaining curation resources still map an unparseable 2xx to "the service may not be running."
CurationAdmission.ts,CurationExplanation.ts,CurationPublish.ts,CurationStoredCopy.tsandCurationVerification.ts. The same defect was closed inCurationSelection.tsandCurationReconciliation.tstoday. Ticket 43 holds it, open, and says why it is five jobs rather than one helper: the copy a curator reads is new Thai text on five surfaces and this repository has no message catalogue, so a person has to review it. - Ten Prisma migrations exist and none has ever been applied to a live Postgres. The api's suite runs without a database because the serialiser is a pure function over rows. Nothing has proved the migration chain applies, or that the schema it produces is the one the tests assume.
- The owner blockers that have not moved, restated only so this file does not read as though the day changed them: the Study Area, The Plant's SDS binder, the spend cap, and the site authority for the Curated Escalation. They are blockers 1 to 4 above and every one is still the human's.
This session — the documentation site
docs/guide/ described the repository as it was on 2026-09-10. Nineteen rulings across three repositories had landed since. The page whose whole job is to be true about the repository, docs/guide/current-state.md, claimed 47 ADRs and 104 decisions against a real 75 and 148, and quoted a git ls-files -s app/ block naming two commits the gitlinks had moved off. Every number on that page is now re-derived by running the command printed beside it.
Changed: docs/guide/current-state.md (rewritten), content-split.md, corpus-lifecycle.md, cost.md, curation.md, data-model.md, architecture.md, identification-and-routing.md, sources-and-data.md, the site's front page index.md, and two stale counts in comments — .vitepress/config.mts and scripts/gen-decision-index.mjs. docs/guide/decisions.md is generated and was already current. All of it landed in 4a8596a.
The rule held throughout: a guide page never states a decision. Every ruling that moved today entered the guide as a row in a | Question | Ruling | table pointing at its ADR, never as a sentence asserting what was ruled. coverage_check.py does not scan docs/guide/, so a paraphrase there is an unwatched second source of truth — which is the defect this pass existed to remove.
bun run docs:check exits 0: 75 ADRs and 148 decisions indexed, the VitePress build clean with ignoreDeadLinks: false, and 6 of 6 mermaid diagrams parsing. No dead link was found; the two supersessions recorded today did not rename a file, and no ADR file has ever been renamed.
One thing this pass found and did not have the authority to fix. The brief it worked from said tickets 39 and 40 are resolved. On disk both read Status: in progress — reviewed 2026-09-20 (frontend 2e383f9); the review's own findings are what remain, and each still carries unchecked boxes. Several of those findings were ruled today (ADR-0060, ADR-0062, ADR-0067, ADR-0068), so the status lines may well be closeable — but deciding that a review's findings are closed is a judgement about the work, not a documentation sync, and the guide records what the ticket files say. Someone who knows that work should read tickets 39 and 40 against today's rulings and either close them or say what is left.
Recommended next step
Run ./init.sh at the root, in app/chemical-safety-assistant-frontend and in app/chemical-safety-assistant-api — all three, because the api's gate is the one that spent seven days red while nobody ran it. All three should print RESULT: PASS; if any does not, that redness is newer than this file and is yours. Gate on the exit code, not on a grep of the summary.
Then grill ADR-0076..0083 before anything else — they are ungrilled, which is what keeps stage 1 open. /to-tickets was the next step before the prototype-feedback round and is now the step after the grill, not before it: stage 3 would otherwise write tickets from rulings no second reader has seen. It is disable-model-invocation: true, so a human types it. An agent that starts it alone has skipped a gate.
One thing to settle with the owner before /to-tickets. All fifteen of D-154..D-168 land at "Implementation Decisions §N" and at no US-nn: no user story says a Handler opens the original document, or that a Curator is shown a page someone already verified. The Coverage gate does not care — a spec may exceed its research, and a decision may exceed its stories — but stage 3 reads US-nn, so either a stage-2 pass adds stories for the new surfaces, or the owner rules that these tickets trace to D-nn alone. Nobody has been asked.
Both gates were fully green when this was written, for the first time today — root six of six, frontend four of four, 802 tests. Anything red after this is newer than this file.
Before planning work from the PRD, know which Coverage rows still say "owed at the next spec pass". That was six rows when this paragraph was first written — D-128, D-129, D-134, D-136, D-144, D-145 — and the parallel session closed all six at 952ce9b. Two remain, D-148 and D-149, both allocated after that commit: the gaps-read union and its precedence (ADR-0071), and the shape a Section crosses the snapshot seam in (ADR-0072). Derive the list rather than trusting this paragraph: grep -n 'owed at the next spec pass' spec/PRD.md.
Do NOT
Dead ends already walked. Each one cost time this session.
- Do not read a file with
catorgrepvia Bash before editing it. Thertkfilter returns stale or truncated content — it served a days-oldAGENTS.md, hid ADR filenames fromls, and silently dropped lines frommain.css. Three separate wrong conclusions came from this. Use theReadtool for anything you will edit, andpython3heredocs to search. - Do not "fix"
SnapshotSeam.spec.tsby renaming the sibling directory. The import namingchem-assistant-api/was the defect; ADR-0063 (D-137) rules the directory ischemical-safety-assistant-api/and the shortened form never existed on disk. Already fixed by the parallel session — the frontend gate is green. - Do not replace "chrome" with "Conversational Content." Tried and reverted. "chrome" is house vocabulary in nine files and is narrower: Conversational Content may be model-generated, and an emergency control's wording may not.
CONTEXT.mdnow glossesChrome. - Do not add glossary terms for
Boot SplashorFirst Run Notice. The owner ruled the two concepts are glossed and the two surfaces live in the ADRs. A Griller's check 3 will flag them every time; it is expected. - Do not take the next free id from disk without checking for a live allocation file. D-128..D-132 were taken mid-session by a parallel session's
rulings-2026-09-20.md. This session had already written five PRD Coverage rows against them, which for a few minutes asserted that D-131 landed as the Boot Splash closed set while the other allocation defines it as a document's page count. - Do not fabricate Coverage rows to clear a COVERAGE red you did not cause. Ten problems today belonged to another session; writing landings for them would have been inventing traceability.