Main - #1
Merged
Merged
Main#1
Conversation
- Replace unrelated 'Portfolio template' theme (index.html, static/) with a minimal placeholder page. - Remove stray unrelated files (HotelList.txt, chat_log.md). - Move planning docs into docs/ (STATUS, DATA_MODEL, VISUALIZATION, IMPLEMENTATION_PLAN) matching the paths AGENTS.md/README.md already point to. - Add source/, tools/, css/, js/, data/ scaffold per the recommended site structure, each with a short README stating its purpose. - Add source/world_history_chart_dataset_v2.xlsx as the human-editable source of truth (198 Boxes, 83 SEAIs, 390 Population rows, 89 Regions rows; verified against docs/STATUS.md counts, no duplicate/orphan IDs found). - Add ISSUES.md and TRACEABILITY.md, and document the branching / issue-tracking / milestone-council-review workflow in AGENTS.md. - Tidy .gitignore (was a placeholder).
- Three-lens council review (data integrity, static-site architecture, process/docs consistency) found no gatekeeper issues. - Fix process/docs reviewer's nits inline: ISSUES.md severity field now uses the declared enum consistently, every issue has an explicit Status field, file a new minor ISSUE-005 for the 6 Boxes rows with no start_year (benign, documented poster-illegibility gap). - Clarify AGENTS.md milestone review process: define 'milestone branch', require a minimum of 3 review lenses including process/docs consistency, specify who reconciles findings and the expected report format. - Ignore .serena/ entirely (tool-local metadata, was partially untracked). - Record council verdicts in ISSUES.md and TRACEABILITY.md.
- Add tools/wh_data.py: shared workbook loader + validation, with an explicit ERROR (structural, fails build) vs WARNING (content-quality, reported only) severity split, documented back into docs/DATA_MODEL.md #8. - Add tools/build_data.py: source/*.xlsx -> data/*.json, refuses to write output when any ERROR-level problem is found. - Add tools/validate_data.py: same validation, report-only, no writes. - Verified against the real workbook: 198/83/390/89 rows load cleanly, 0 errors, 671 warnings (198+83 TODO URLs, 390 unfilled population rows -- all expected per docs/STATUS.md). - Verified the failure path against a deliberately corrupted copy of the workbook (duplicate box_id, invalid color_hex, cascading FK break): build exits 1 and writes nothing. - Commit generated data/boxes.json, data/seais.json, data/population.json, data/regions.json -- the static site has no build step in production, so these are checked in like any other build artifact. - File ISSUE-006 (no automated test suite yet) and update TRACEABILITY.md with Milestone 1's requirement closure table.
Three-lens review (data integrity, static-site architecture/constraints, process & documentation consistency) completed with no gatekeeper findings: - Data integrity: PASS - Architecture/constraints: PASS - Process/docs: PASS_WITH_MINOR_ISSUES Fixed inline: - ISSUE-005 was misfiled under '## Resolved' despite its own Status field saying Tabled since Milestone 0; moved to '## Tabled'. - tools/README.md now points at tools/requirements.txt instead of a bare 'pip install openpyxl'. - docs/STATUS.md refreshed to mention the build/validation pipeline. Filed as tabled minor issues (not gatekeepers): - ISSUE-007: dead code in wh_data.py's vocabulary-check loop (estimate_method branch can never fire). - ISSUE-008: malformed/corrupt workbook produces a raw Python traceback instead of a clean CLI error (fails safely either way). TRACEABILITY.md and ISSUES.md updated with the Milestone 1 council review record.
Council review: data integrity PASS, architecture/constraints PASS, process/docs PASS_WITH_MINOR_ISSUES. No gatekeeper findings. See ISSUES.md and TRACEABILITY.md for details.
A genuinely interactive first slice: load the generated JSON, list all Boxes sorted by start year with color swatches, click to select and see an inspector panel (name, dates, region, span, confidence, notes, URL, linked SEAIs), and filter the list by region_group. - js/data.js: loadAllData() fetches data/*.json in parallel and builds boxesById/seaisByBoxId/populationByBoxId indices; regionGroups() for the filter control. - js/state.js: createStore(), a minimal pub-sub state container with the field shapes from docs/IMPLEMENTATION_PLAN.md Phase 2. - js/app.js: wires data + state + DOM rendering; no framework, plain ES modules per AGENTS.md. - css/history.css: minimal responsive styling; light/dark via prefers-color-scheme; selection state carries a checkmark + bold text, not just background color (AGENTS.md accessibility: color isn't the sole encoding); list items are real <button>s so click/keyboard both work with no hover-only interaction. - index.html: real layout (header/status/summary, region filter, box list + inspector panels, footer), loads js/app.js as an ES module. Runtime-verified with Node (built-in fetch, v18.15.0) against a local static server and a minimal DOM stub (no browser available in this environment): confirmed loadAllData/regionGroups against the real data/*.json, createStore's subscribe/set/unsubscribe semantics, and the full app.js wiring end-to-end (initial render shows 198 boxes/83 SEAIs/390 population rows/89 region rows, 13 region-filter options, click-to-select renders the correct inspector content, region filter narrows the list and clears selection). node --check passed on all three new JS files (via temporary .mjs copies, since this repo has no package.json declaring module type).
Marks V1-1/V1-2/V1-5/V1-6/V1-7 Met against the Milestone 2 slice; V1-3/V1-4 (Sankey/alluvial, timeline) remain Not started (Phase 3/4). Council review for Milestone 2 pending.
Three-lens review completed with no gatekeeper findings: - Data integrity: PASS_WITH_MINOR_ISSUES - Architecture/constraints & accessibility: PASS - Process/docs: PASS_WITH_MINOR_ISSUES Fixed inline: - js/app.js: filteredBoxes sorted the 6 null-start_year boxes (ISSUE-005) by their *end* year, misplacing prehistoric-era boxes (e.g. an Indigenous Era box ending 1607) next to 16th-century boxes instead of near other prehistoric-start entities. Sort fallback changed from '?? end_year ?? 0' to '?? Number.NEGATIVE_INFINITY'; re-verified with the same Node/fake-DOM harness that the 4 prehistoric-start boxes now sort to the front of the list. - js/app.js: main() had no .catch(), so a rendering-time error (as opposed to an already-handled fetch failure) would only surface as a silent unhandled-rejection warning. Added main().catch(...) routing to the same error-display path. - js/README.md: rewritten to describe the actual data.js/state.js/app.js split instead of a since-superseded planned module list. - docs/STATUS.md: refreshed to mention the Phase 2 prototype. Filed as tabled minor issues (not gatekeepers): - ISSUE-009: no automated test suite for js/app.js|data.js|state.js (parallel to ISSUE-006's Python-side gap). - ISSUE-010: milestones have landed as one or two large commits rather than the frequent-small-commits granularity AGENTS.md describes. TRACEABILITY.md and ISSUES.md updated with the Milestone 2 council review record; M2-9 downgraded from Met to Partial pending ISSUE-009.
Council review: data integrity PASS_WITH_MINOR_ISSUES, architecture/ constraints & accessibility PASS, process/docs PASS_WITH_MINOR_ISSUES. No gatekeeper findings; a real sort-order bug and an unhandled-rejection gap were fixed inline before merge. See ISSUES.md and TRACEABILITY.md.
Pure file move (git detects all as renames, no content changes yet). The whole tree moves together so internal relative paths (index.html -> css/js, js/app.js fetching data/, tools scripts reading source/) are unaffected; only external pointers into this project (AGENTS.md, README.md) need updating in a follow-up commit. Part of the site restructure: root becomes a personal landing page, projects/<name>/ holds each project. See docs/IMPLEMENTATION_PLAN.md and the Milestone 3 TRACEABILITY.md entry (added in a later commit).
- New root index.html + css/site.css: modest personal landing page for erikson1970, Viking/Nordic/French-themed (navy/forest-green, gold/bronze accents, serif display headings, CSS-only knotwork divider, no image assets). Uses user-provided bio copy verbatim. Links to projects/world-history/ and is designed for future project cards. - Root README.md rewritten for the personal-site/multi-project framing; old world-history-specific README.md content preserved at projects/world-history/README.md with a historical note about the move. - AGENTS.md: new "Repository structure" section; all project-specific paths (docs/, source/, tools/, css/, js/, data/) updated to projects/world-history/; milestone-branch definition extended to cover site-level changes. - ISSUES.md/TRACEABILITY.md: kept shared at root per user's explicit choice (one continuous history, not split per project); both given a "Path note" explaining pre-Milestone-3 entries reference now-superseded root-relative paths rather than rewriting history. - projects/world-history/tools/README.md: clarified that build/validate script default paths are relative to the project directory, so they must be run with projects/world-history/ as the working directory. - TRACEABILITY.md: added Milestone 3 requirements table (M3-1..M3-7), all Met, evidence includes the local-server/curl/Node/validate_data.py verification already performed against the moved project tree. Council review pending before merge to main. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Three lenses (path/link integrity, architecture/accessibility, process/docs consistency) reviewed commit ce8b234. No gatekeeper findings. Fixed inline: - Wrapped project-card links in <h3> (index.html, css/site.css) so screen-reader heading navigation works once more project cards are added. - Added missing fonts.googleapis.com preconnect alongside fonts.gstatic.com. - Extended TRACEABILITY.md's Path note to cover README.md section citations (Milestones 0-2 cite headings that moved wholesale to projects/world-history/README.md in Milestone 3). - Downgraded TRACEABILITY.md M3-4 from Met to Partial: the Node loadAllData() verification was never captured as a committed, repeatable test, same gap as ISSUE-009 (extended that issue's description to note the recurrence). Noted, not newly filed: Milestone 3 again landed as two large commits, consistent with already-tabled ISSUE-010. Council review record added to ISSUES.md and TRACEABILITY.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Root becomes a personal landing page for erikson1970; World History Explorer moves to projects/world-history/. Council-reviewed, no gatekeeper findings. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add a 7-row hand-authored Links sheet to the source workbook covering the Mediterranean/Europe subset from docs/IMPLEMENTATION_PLAN.md Phase 3 (Roman -> Western Roman/Byzantine, Frankish -> West/East Francia, West Francia -> Kingdom of France, East Francia -> Holy Roman Empire, Byzantine -> Ottoman). Each row has a real Wikipedia source_url, High confidence, and substantive notes. Extend tools/wh_data.py with validate_links(): checks link_id uniqueness, source/target FK existence, malformed year, and relation_type membership -- classified as ERROR (not the usual WARNING-for-vocabulary default) per IMPLEMENTATION_PLAN.md Phase 1's explicit "fails on unknown relation types" requirement. Year-outside- span is a WARNING (content-quality, not structural). Wire into build_data.py as a new links.json output. Verified: validate_data.py runs clean (671 warnings, 0 errors, unchanged from before -- Links adds 0 new warnings), build_data.py writes links.json with all 7 rows correctly, and a deliberately corrupted relation_type / broken FK correctly blocks the build (ERROR, exit 1, no output written).
Add js/sankey.js: buildSankeyFigure(links, boxesById) is a pure data transform (node x from start_year, clamped [0.02, 0.98]; arrangement: "fixed" to strictly enforce chronological left-to-right node order per AGENTS.md Visualization semantics -- no auto-layout reordering). renderSankey(container, data, callbacks) wraps Plotly.newPlot and plotly_click handling, routing node clicks to onSelectBox and link clicks to onSelectLink. Wire into js/app.js: selectedLinkId added to js/state.js's initialState so a clicked link drives the same inspector panel as a clicked box (mutually exclusive -- box-list clicks and region-filter changes clear selectedLinkId and vice versa). renderSankey() is called inside a try/catch so a Plotly load failure (offline, CDN blocked) degrades to a text fallback in the alluvial container without breaking the box list/inspector/filter. js/data.js: load links.json, build linksById and linksByBoxId indices. index.html: load Plotly 2.35.2 from cdn.plot.ly (pinned exact version, reachability verified), add the alluvial section with a role=img/aria-label container and a note that ribbon width is placeholder equal-weighting, not population-based (see docs/VISUALIZATION.md, ISSUE-003). Verified via a Node fake-DOM harness (fetch redirected to a local static server, no window.Plotly to exercise the fallback path): data loads, 198 boxes render, region filter (13 options) narrows the list correctly, box click populates the inspector, the alluvial container falls back to a caught error message as designed. Real-browser Plotly rendering/click-interaction is not verifiable in this environment -- see TRACEABILITY.md M4 for the resulting Partial caveat.
Add the Milestone 4 section to TRACEABILITY.md (M4-1 through M4-10), covering IMPLEMENTATION_PLAN.md Phase 3's acceptance criteria and retroactively covering Phase 1's Links validation requirement (M1-6, previously Not started). M4-6/M4-8 marked Partial: the pure data transform, pipeline, and non-Plotly UI wiring are verified, but real browser/Plotly click-interaction can't be confirmed in this environment. Update the v0.1 definition-of-done table (V1-3, V1-5). Add a Milestone-4 note to ISSUES.md's ISSUE-004 (partial resolution for Links, BoxSegments still fully open) without rewriting the original entry, per the historical-record-integrity precedent from earlier milestones. Refresh docs/STATUS.md (Phase 3 alluvial prototype described, Links recommended-work item marked done-for-a-subset, succession-not-modeled limitation updated) and js/README.md (document sankey.js).
Three-lens review (data integrity, static-site architecture/accessibility,
process & docs) all PASS_WITH_MINOR_ISSUES, no gatekeeper findings.
Fixed inline:
- Accessibility gap: the Plotly widget alone gave keyboard/AT users no
way to browse or select a link. Added #alluvial-list, a visually-hidden
(visible on :focus-within) list of real <button>s -- one per link --
that call the same onSelectLink path as a chart click. Verified via the
fake-DOM harness: 7 items render, clicking one populates the inspector.
- Theme bug: the Sankey chart ignored the page's dark mode (Plotly
defaults to opaque white). renderSankey() now reads --bg/--fg off
:root and sets paper_bgcolor/plot_bgcolor/font.color.
- Robustness: links.json was fetched in the same Promise.all as the
required tables, so a broken Links file could take down the whole
page. Split into required (hard-fail) vs. optional (catch, default
to [], warn) fetches in js/data.js.
- Latent NaN node-position bug if a future subset had no box with a
numeric start_year (Math.min/max of an empty array, -Infinity || 1
still -Infinity); now guarded.
- Un-awaited Plotly.newPlot promise: an async rejection would bypass
the intended fallback message. renderSankey() is now async and
awaited by its caller inside the existing try/catch.
- Misleading alluvial-note prose that read as one chained succession;
reworded to list the 7 discrete links.
- JSDoc gap (linksById missing from loadAllData's comment).
- Opaque validation message for a missing relation_type ('relation_type
None not in [...]' -> 'missing relation_type').
Tabled as a new issue: ISSUE-011 (DATA_MODEL.md's 'transition year
sensible' check is a loose union-envelope heuristic). Extended existing
entries: ISSUE-009 (third recurrence of uncommitted runtime JS
verification), ISSUE-010 (commit granularity improved to 3 commits this
milestone). Reworded TRACEABILITY.md M4-6/M4-7/M4-8 so the Partial
ratings don't overclaim relative to what the fake-DOM harness actually
exercised vs. what still needs a real browser.
- js/timeline.js: buildTimelineLayout() (pure, Node-testable) + renderTimeline() (D3 SVG). One bar per in-view box, ordered chronologically, colored by color_hex, with diamond SEAI markers and a year axis. - Year-range (From/To year) and Show SEAIs controls wired to js/state.js's existing yearStart/yearEnd/showSeais fields. - The 6 ISSUE-005 boxes with no legible start date get a dashed left edge clamped to the current view's left boundary, not a fabricated date. - Deliberately no independent hidden-list fallback for the timeline: every box it draws is already keyboard-selectable via the existing box list. - D3 7.9.0 loaded via pinned cdnjs CDN script, same pattern as Plotly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fixed inline: reversed year-range bug (js/app.js now rejects yearStart > yearEnd before it reaches the store), dead SEAI tooltip (pointer-events:none on .seai-marker), wrong evidence numbers/citations in TRACEABILITY.md, imprecise code comment in timeline.js. Closed ISSUE-009's would-be 4th recurrence with an actual fix instead of re-tabling: js/timeline.test.mjs is a committed, repeatable test for buildTimelineLayout(), enabled by a new root package.json declaring type:module (browser loading via index.html is unaffected). Backfilled a missing 'Milestone 4' section in ISSUES.md (referenced by TRACEABILITY.md and commit 09eea5f but never actually written), added the Milestone 5 section, filed ISSUE-012 (timeline resize + a few prehistoric-SEAI edge cases), annotated ISSUE-003/005/010, and superseded V1-4 in TRACEABILITY.md's v0.1 table. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… traceability User-authored docs/timescaleRequirement.md specifies a nonlinear year->x mapping for the timeline (recent history gets more horizontal room in wide views, relaxing toward linear as the view narrows), shared across every time-based element in a view and user-tunable via a [-2,2] slider. Not implemented yet -- this commit only records the requirement: - docs/IMPLEMENTATION_PLAN.md: new Phase 5.5, ordered before Phase 6 since population knot points need the same scale; notes it revisits Phase 3's Sankey and Phase 4's timeline x-positioning (both currently linear). - TRACEABILITY.md: new 'Planned -- Phase 5.5' section, TS-1..TS-10.
…x-list)
Selecting a box or link anywhere on the page now updates every panel:
- js/sankey.js: applySankeySelection() re-colors the already-rendered
Sankey trace via Plotly.restyle (node outline for a selected box, link
color for a selected link) without re-registering plotly_click.
computeSankeyHighlight() is the pure, Node-testable split of that
computation, matching buildSankeyFigure/buildTimelineLayout's existing
pattern. renderSankey() now resolves {boxIds} so app.js can drive this.
- js/timeline.js: renderTimeline() accepts state.linkHighlightBoxIds, an
optional Set marking a selected link's two endpoint boxes with a new
.link-endpoint class (distinct, non-dashed, from .approx-start).
- js/app.js: renderAlluvialListSelection() toggles .selected/aria-pressed
on the alluvial-list buttons (mirroring the box list's own pattern);
renderTimelineView() resolves selectedLinkId to its endpoint box_ids;
renderSankeySelection() wires applySankeySelection() into the store
subscription, plus a catch-up call right after renderSankey() resolves
in case a selection happened elsewhere while Plotly was still loading.
- css/history.css: #alluvial-list button.selected (background + bold +
checkmark, not color alone) and #timeline .timeline-bar.link-endpoint.
- js/sankey.test.mjs: new committed test (buildSankeyFigure, previously
untested, plus computeSankeyHighlight) -- 20 assertions, all passing.
Deep-link URL query params (the plan's own 'possible future' example) are
explicitly out of scope for this milestone -- see TRACEABILITY.md M6-6.
Also: docs/STATUS.md, js/README.md, index.html notes, and TRACEABILITY.md
Milestone 6 (M6-1..M6-9) updated to describe the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Accessibility gatekeeper: Sankey selected-link was color-only encoded (ribbon color, no other channel). computeSankeyHighlight() now also outlines the selected link's two endpoint nodes via node.line, same mechanism a selected box already used. Tests updated accordingly. Architecture gatekeeper: ISSUES.md was missing a Milestone 6 note on ISSUE-009 despite js/sankey.test.mjs and TRACEABILITY.md both pointing at it. Added. Minor fixes applied inline: .link-endpoint CSS now resets stroke-dasharray so it reads solid even on an .approx-start box; TRACEABILITY.md's status vocabulary now lists "Deferred"; js/README.md's sankey.js paragraph now mentions sankey.test.mjs. TRACEABILITY.md and ISSUES.md gain the full Milestone 6 council-review write-up (3 verdicts, findings-and-fixes), matching the Milestone 4/5 pattern. Verified: node --check on every changed .js file, and both js/sankey.test.mjs (23/23) and js/timeline.test.mjs pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…sync) Phase 5: selecting a box or link anywhere (box list, alluvial-list, Sankey diagram, timeline) syncs the shared selection state and reflects it across every panel. Extends the pure/DOM-split pattern from prior milestones (computeSankeyHighlight/applySankeySelection). Also folds in docs/timescaleRequirement.md (user-authored) as Phase 5.5 in docs/IMPLEMENTATION_PLAN.md, and records it (TS-1..TS-10) in TRACEABILITY.md as documentation only, not yet implemented. Full 3-lens council review run; both gatekeeper findings (Sankey selected-link color-only encoding, missing ISSUES.md note) fixed before merge. See TRACEABILITY.md's Milestone 6 section for details. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New js/timescale.js: a pure, Node-testable semanticTimeScale({tMin, tMax,
scaler}) implementing docs/timescaleRequirement.md's nonlinear mapping
(x = 1 - (a/M)^p, p = 1/(1 + (M/3000)*2^s), the multiplicative form the
doc requires) plus calendar-time-first timeTicks(). No D3/DOM/Plotly
dependency, so both the timeline and the Sankey diagram can share one
scale instance without either depending on the other's rendering stack.
js/state.js gains state.timeScale (the slider's `s`, [-2, 2], default 0).
js/timeline.js: buildTimelineLayout() now builds one shared scale from
[state.yearStart, state.yearEnd, state.timeScale] and uses it for every
box bar, SEAI marker, and axis tick -- no more per-element linear
normalization. renderTimeline() drops d3.scaleLinear/d3.axisBottom for
the new scale plus a hand-built axis (same .timeline-axis/.domain/.tick
CSS classes, so no styling changes needed), with explicit "N BCE"/"N CE"
tick labels instead of a raw signed number.
js/sankey.js: new computeSankeyNodeX(boxIds, boxesById, state) replaces
buildSankeyFigure's old per-subset min/max normalization with the same
shared scale and the app's global year range -- Sankey node x now lines
up with the timeline's x-axis exactly, per the spec's "Shared Scale"
list. buildSankeyFigure/renderSankey take a new `state` argument; a new
applySankeyTimeScale() (kept separate from the existing
applySankeySelection(), same split reasoning as buildSankeyFigure vs.
computeSankeyHighlight) re-positions nodes via Plotly.restyle when the
shared state changes. The node *set* is still driven only by
data/links.json, unfiltered by year range -- only node x changed.
js/app.js: new #time-scale slider wired to the `input` event (continuous
update while dragging, per the spec's "Zoom Interaction"), threading
state into renderSankey()'s call and adding a renderSankeyTimeScale()
subscriber alongside the existing renderSankeySelection().
index.html: adds the "Time compression (ancient detail <-> recent
detail)" range input; updates the timeline/alluvial notes and footer to
describe the now-shared, page-wide scale. css/history.css: sizes the new
range input.
Tests: js/timescale.test.mjs (new, 212 assertions covering the spec's
own Validation section -- boundary, monotonicity incl. out-of-domain
years, round-trip, zoom/slider behavior, coordinate stability, tick
generation). js/timeline.test.mjs and js/sankey.test.mjs extended for
the new scale/x0/x1/ticks fields and computeSankeyNodeX.
Docs: TRACEABILITY.md's "Planned -- Phase 5.5" placeholder becomes
"Milestone 7", TS-1..TS-11 (TS-11, optional smooth-animation-while-
zooming, Deferred -- logged as ISSUES.md ISSUE-013). docs/STATUS.md and
js/README.md updated to describe the new module and its integration.
Deferred (ISSUE-013): smooth animation while zooming/dragging -- framed
as optional in the source spec, not attempted this milestone.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
3-lens review of 887f483: Correctness/data-fidelity PASS, Architecture/ docs PASS, Accessibility/UX PASS_WITH_MINOR_ISSUES. Gatekeeper fix: js/timescale.js's timeTicks() now excludes an exact-0 tick candidate -- js/timeline.js's formatTickYear was rendering it as "0 CE", a year docs/DATA_MODEL.md documents doesn't exist in this dataset's BCE/CE convention, and the app's own default -3000..2026 view produced exactly such a tick. formatTickYear also independently guards year 0 (and the -0 Math.round can produce) for any future reuse as a hover/inspector label. New timescale.test.mjs assertions cover both a straddling-zero span and a smaller-interval one. Minor fixes: js/sankey.test.mjs now exercises computeSankeyNodeX's null-start_year (ISSUE-005) fallback with a synthetic box; js/timeline.js's tick rendering reuses buildTimelineLayout's precomputed x instead of recomputing scale.yearToX(year) a second time per tick. Tabled: ISSUE-013 (smooth zoom animation, optional per spec, already filed) and new ISSUE-014 (time-scale slider's input listener re-renders every panel, not just timeScale-dependent ones -- no debounce/RAF throttle). ISSUE-010 (commit granularity) noted as regressed further this milestone. TRACEABILITY.md gains a "Milestone 7 council review" section; ISSUES.md gains the matching "Milestone council reviews" write-up plus ISSUE-014 and Milestone-7 notes on ISSUE-010/ISSUE-013. Milestone approved to merge to main. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ale)
Implements Phase 5.5 / docs/timescaleRequirement.md's semantic-zoom time
scale (TS-1..TS-10 in TRACEABILITY.md): a shared, pure semanticTimeScale()
(js/timescale.js) used by every time-based visual element -- timeline bars,
SEAI markers, axis ticks, and Sankey node x -- via a single -2..2 slider
(js/app.js/index.html) that recomputes continuously on the `input` event.
Highlights:
- js/timescale.js: semanticTimeScale({tMin, tMax, scaler}) implementing
p = 1 / (1 + (M/3000) * 2^s), x = 1 - (a/M)^p; timeTicks() generates
candidate tick years in calendar time first, then maps them through the
shared scale (never the reverse).
- js/timeline.js, js/sankey.js: both now route all time-based x-positioning
through one shared scale instance per render, per the spec's "Shared
Scale" requirement.
- js/state.js, js/app.js, index.html, css/history.css: new timeScale state
field and #time-scale slider control, continuous input-event updates.
Council review (3 lenses -- correctness/data-fidelity: PASS; accessibility/
UX: PASS_WITH_MINOR_ISSUES; architecture/docs: PASS) found one gatekeeper:
a calendar-arithmetic tick landing on year 0 rendered as "0 CE", which isn't
a real year under this dataset's BCE/CE convention (docs/DATA_MODEL.md:
"There is no attempt to model a historical year zero"). Fixed in
timeTicks() itself, with js/timeline.js's formatTickYear also hardened
defensively. Two other minor findings were fixed inline (untested
null-start_year Sankey fallback; redundant yearToX recompute in tick
rendering); two more were tabled as ISSUE-014 (new) and a note on
ISSUE-010, per the same reconciliation process as prior milestones. Full
writeup: TRACEABILITY.md "Milestone 7 council review", ISSUES.md
"Milestone 7 -- Semantic zoom time scale (Phase 5.5)".
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Main into Master - then we'll