Pending work for aggregate_api, newest thinking at the bottom of each list.
What has landed is in CHANGELOG.md and the git log; completed plans move to
dev/done/.
Items oddly from the aggregate list
- [Session-Build-Clobbers-The-Trailer]: a session
build(...)of a program that shadows a library name replaces the library entry'snote{}andtags{}.
-
[Short-Links] DONE (
1.43.0), plandev/done/plan-short-links-and-cards.md. Copy link copiesagg.mynl.com/x/<code>, 5 characters for the entry and 3 for the tab, hashed and never stored; long links still work./x/<code>returns a link preview card (name, note,social-card.png) and the site has a generic one. Still owed, the author's: deploy, then opengraph.xyz, LinkedIn Post Inspector and Facebook Sharing Debugger on a short link and on the bare site. -
[API-Editable-Aggregate-Source] DONE (
1.42.0), plandev/done/plan-api-editable-aggregate-source.md.aggregateinstalls editable from../../worktrees/aggregate_REFACTORthrough[tool.uv.sources], souv synckeeps the worktree library; the dependency isaggregate[elt]>=1.61.0with no ceiling, andtests/test_private_names.pyguards the two private names. Still owed, the author's: the VPS symlink~/worktrees/aggregate_REFACTORbefore the nextrefresh.sh, and the two skill edits drafted in the plan's log. -
[Follow-Aggregate-1.61] DONE (
1.41.0), no plan: the two follow-ups aggregate 1.56.0 and 1.59.0 name for the API. The strip grades each clause of a reinsured verdict, so a clean net view is green, and an unmatched bracket is the library's parse error with its position. -
[Multi-Statement-Programs] DONE (
1.40.0), plandev/done/plan-multi-statement-programs.md. The box takes several statements, the statements before the last are filed and only the last is built, and the API refuses whatbuild()refuses, for every client. Controls that transform the box refuse several statements in the status strip. Left open: Sharpen, Hints and Cede act on the last built object when one statement was edited and not built;POST /v1/decl/parsestill parses each statement against the default base; Reformat keeping references needs a library plan (option [c] in the plan). -
[Chfagg-Aggregate-Parity] DONE (
1.38.0), no plan: the consumer half of aggregate 1.35.0 to 1.41.0. Achfaggtakes the arithmetic form, Evaluate and Sharpen run on it, with the More Sharpen leaf and thebs_windowandtail_behaviorexhibits, and the word list follows 1.41.0. The floor landed at 1.42.0,[API-Editable-Aggregate-Source]. -
[Chfagg-Kind] DONE (
1.37.0), no plan: the library'schfagglaw (aggregate 1.30.0 to 1.34.0) builds, prices and exports, and the word list follows 1.34.0. Owed upstream:_KIND_WRITE_ORDERwritesaggbefore thechfaggit references, so the library's own.aggexport does not reload. -
[Status-Bar-Text-Answers] DONE (
1.36.0), plandev/done/plan-status-bar-text-answers.md. A conversion statement (tweedie,stable) answers as text in the aLL strip and as the cell value in Excel and Sheets; the word list follows aggregate 1.23.0 andyltbecameyelt. Still owed, the author's:npm run pushfor the Sheets template. -
[Eltq-Version] DONE (
1.35.1), no plan: About,/v1/metaand the status page list the eltq version. -
[Loss-Table-File-Gate] DONE (
1.35.0), plandev/done/plan-loss-table-file-gate.md. A loss table file path is read for private requests only: the request text, references through the preview, and the object cache. Still owed, the author's: deploy to the VPS, and192.168.4.0/24inAGGAPI_PRIVATE_CIDRSon DOOB's launcher. Optional later: a library switch that refuses file sources at the read, as a second layer. -
[ELT-Keywords-And-Eltq] DONE (
1.34.0), no plan: the consumer half of the library's loss tables,aggregate1.12.0 to 1.18.0.eltq>=2.13as a direct dependency and the word list regenerated against 1.18.0.aggregate[elt]and the floor landed at 1.42.0,[API-Editable-Aggregate-Source]. -
[Menu-Preferences] DONE (
1.33.0), no plan: tire kicking on a phone. Tables, Perspective and Editor collapse under a Preferences row after Apps, and the menu scrolls within the screen. Still owed, the author's: the check on a real phone. -
[Greater-Tables-8] DONE (
1.32.0), plandev/done/plan-greater-tables-8.md, the consumer half of the library's [Format-Sheet-Block-Filter] (aggregate1.10.0, on PyPI as 1.11.0). Floorsgreater-tables>=8.1.0andaggregate>=1.11.0; no greater_tables warning in any response. Still owed, the author's: the plugin's re-lock to greater-tables 8.1.0, uncommitted inaggregate-relativity, and the by-hand acceptance against the restarted server. -
[Excel-Library-And-Frames] DONE (
1.22.0to1.26.0), plandev/done/plan-excel-library-and-frames.md, five steps, one bump each:[lab-all-rows-switch]1.22.0 (All rows as a menu item and Ctrl+Shift+A, the density grids window, nine seconds to one),[readable-arguments]1.23.0 (#AGG!for every refusal,pon[0, 1]),[frames-route]1.24.0 (GET /frames,AGG.FRAMES,AGG.FRAMEURL),[library-functions]1.25.0 (AGG.LIBRARY,AGG.PROGRAM),[pane-frames]1.26.0 (the pane's Whole frames section). Still owed, the author's: the Excel acceptance list in desktop Excel (npm stop,npm start, then the plan's four items), the Ctrl+Shift+A check in Edge and Firefox, and the deploy. Upstream ask forcsv-grid: refresh the status line after_applyHeight. -
[Excel-Program-Ranges] DONE (
1.21.0), no plan: tire kicking after 1.20.0. The three handle-taking functions accept a program as a range, a refused program returns#DECL!and the reason as cell text, and the development build calls the local 19456 server. -
[Fast-Frames] DONE (
1.17.1to1.20.0), plandev/done/plan-fast-frames.md:[orjson-frames]1.17.1,[gzip-level]1.17.2,[parquet-route]1.18.0,[lab-all-rows]1.19.0,[excel-decl-arguments]1.20.0. Full density frames for the Lab (All rows, 3.5M cell budget), Excel (Power Query over Parquet) and R. Still owed, the author's: the Excel acceptance list in desktop Excel (Power Query and byte stream split among them), the host sync with--extra parquet, and the Caddy check that a.parquetbody is not re-encoded. Findings: the 8.5 s All rows took on 65,536 by 12 was the grid rendering every row unwindowed, not the parse, fixed in 1.22.0 ([Excel-Library-And-Frames]); theexeqa_display binning (right edge, not mass-weighted) is still open; the R client is its own plan, next. -
[Excel-Hosting] DONE (
1.17.0), plandev/done/plan-excel-hosting.md./excelserves the add-in built byscripts/build-excel.ps1(or.sh),no-cache, with a production manifest underhttps://agg.mynl.com/excel. On the host, done: the Caddy limits (verified 2026-10-18), the deploy, andAGGAPI_CACHE_MAX=100(2026-10-20, in the systemd unit). Still owed, the author's: the plan's acceptance list against agg.mynl.com (web in Edge and Chrome, Windows desktop, a version bump reaching a reopened workbook). -
[Excel-Core] DONE (
1.16.0), plandev/done/plan-excel-core.md. Theexcel/add-in:AGG.BUILD,AGG.EXHIBITS,AGG.EXHIBIT,AGG.QandAGG.VERSIONover a local server, with the recipe table, session id, memo and request limit. Still owed: the plan's acceptance list in desktop Excel (npm start), which nothing here could run. Later:[excel-pane],[excel-types],AGG.FRAME. -
[Session-Parse] DONE (
1.15.0), plandev/done/plan-reformat-explodes-session-references.md. Reformat previews the program in the caller's fork and renders each statement's spec, so own declarations inline like library entries and a second statement may name the first. Noweb/change. -
[Server-Parsed-Key] DONE (
1.14.0), plandev/done/plan-cache-key-from-parsed-program.md. The object id hashes the parsed program, its references' stored specs, the grid, versions and the library digest, so a redefined name builds a fresh object and an id means the same thing in any process. Addslibrary_references_onlyfor Excel. Still owed: an upstream ask for a losslessstronDistortionandCopula(see the plan's execution log, divergence 1). -
[Warm-Library] DONE (
1.13.4), plandev/done/plan-1.13.4-warm-library-at-startup.md.create_app()reads the library before serving, so a fresh server's first page load can no longer fork a half-read base (Capstone.ExposureRatingfailing onCapstone.Gross). Still owed: the manual restart check in the plan. The library half landed inaggregate1.5.2,dev/done/plan-1.5.2-thread-safe-load.md. -
[Exact-Tail-Leaf] DONE (
1.13.0), plandev/done/plan-1.13.0-exact-tail-leaf.md, the api half of the library's [NTT-Exact-Tail-Chart] (aggregate1.5.0). More ▸ Exact tail draws the nttagg's exact mass and survival as base-10 exponents beside the float FFT; the adapter learnslog10_densityandlog10_probability. Still owed: the manual checks in the plan (browser draw time onWilson2017.DiceOfDiceamong them), and a ruling on the twonttagg_gapssmoke failures its execution log describes. -
[Deep-Link-View] DONE (
1.10.0to1.11.0), plandev/done/plan-1.10.0-deep-link-view.md, two steps. [view] (1.10.0):view=<group>:<leaf>lands a deep link's build on a named tab, keys or labels in any case, with a note in the strip when the view cannot be shown. [copy-link] (1.11.0): Menu ▸ Copy link writes a link to the entry and tab on screen, againstAGGAPI_PUBLIC_URL(defaulthttps://agg.mynl.com/). Still owed, by eye in a visible window (the plan's execution log says why): the scroll anchor on a view link, tall and short, and thelink copiedclipboard path. Deploying to the public site is the author's. -
[Version-Source] DONE (
1.9.1), plandev/done/plan-1.9.1-version-source.md, shared withaggregate1.2.1,aggregate-relativity0.10.0 andaggregate-ntt. Every version the server reports is read live from__version__, so a bump runs nouv sync. -
[NTT-Version] DONE (
1.9.0), plandev/done/plan-1.9.0-ntt-version.md. About listsaggregate-nttwhen the compiled engine is installed, from/v1/meta.ntt_version. -
[Pentagon-Readout] DONE (
1.8.0, tweak1.8.1), plandev/done/plan-1.6.0-pentagon-readout.md(numbered 1.6.0 when drafted, landed after the DecL help took 1.6.0 and 1.7.0). The PnL group's Pentagon notes moved from Bootstrap tooltips to one fixed readout in the figure's lower-left corner, driven by hover, focus and tap. Still owed: the iPad check on a real device. -
[DecL-Help] DONE (
1.6.0to1.7.0), plandev/done/plan-1.7.0-decl-help.md, two steps, the api half of the library's [DecL-Help-Pages] (aggregate1.2.0a15). [anatomy] (1.6.0): a?above the✕in the program box opens the library's anatomy page in a popover over the dimmed output, with Load buttons that fill the editor without building;GET /v1/decl/helpand/v1/meta.decl_help. [card] (1.7.0): Menu ▸ DecL on one page, the card on a sheet that prints to one Letter landscape page. Both one below the plan's numbers, since the pentagon readout plan had not landed. Still owed, outside the plan: the help reaches PyPI users only onceaggregate1.2.0 ships, and the pin floor moves only if the author wants it guaranteed. -
[Example-Databases] DONE (
1.4.0to1.5.0), plandev/done/plan-1.4.0-example-databases.md, two steps. [databases] (1.4.0): Menu ▸ Examples from picks the shipped.aggfile behind the Examples menu, per viewer, overGET /v1/examples?database=. [deep-link] (1.5.0):/?database=<stem>&example=<name>selects the file and builds the entry, for the paper's links, desktop and phone. Still owed, outside the plan: raise the pin floor to the release carryingaas-paper.aggand deploy. (The twonttaggtests library 1.2.0a13's[NTT-Grid-Cap]broke were fixed after 1.5.0, test only: requestlog2=6for the dice, and a wider program for the binning case.) -
[nttagg-Exact-Log] DONE (
1.3.0), no plan doc: a tweak off the author's 1.2.0 tire-kicking, landing with a library reshape.p_exact_log10joins the Density grid, andserializers.mass_columnsstops the display binning summing it as though it were a mass.p_exactleftdensity_dfat library 1.2.0a7, so the exact rationals are no longer reachable through the api at all; see the note at the end ofCHANGELOG.md1.3.0 and the open item below. -
[nttagg-Density-Column] DONE (
1.2.0), no plan doc: a tweak off the author's 1.1.0 tire-kicking. More > Density asks forp_exact_floaton annttagg, through a per-kind addition to the curated column subset (DENSITY_COLS_BY_KINDinweb/src/main.js) rather than by sending the kind down the whole-frame path. The reading is in the tails, where the float pipeline runs out of precision and the exact answer still has digits. No api change; the route already served the column by name. Detail inCHANGELOG.md1.2.0. -
[nttagg] DONE (
1.1.0), plandev/done/plan-1.1.0-nttagg.md. The library's exact bounded compound (aggregate1.1.0'snttagg) is admitted, served and labeled: four kind touchpoints, theNTT Aggregatelabel in both copies ofKIND_LABEL, the keyword in the editor's pool, and the exact rational column kept out of both display payloads while the CSV keeps it.capability.pydeliberately untouched; the composability fix was the library's and landed inaggregate1.2.0a3. Detail inCHANGELOG.md1.1.0.-
_KIND_OF_CLASS,SUPPORTED_KINDS,_KIND_ORDER,BuildResponse.kind. The last is not cosmetic: a kind the route classifies and the response model does not list 500s after the build has run. -
p_exactout of the JSONdensity_dfand theformat=irdocument, through one shared helper so the two display paths cannot drift. The headline case puts a 410-character rational in a cell, and the column also matches thep-prefix test that decides what a display grid sums. - Tests gated on the parser rather than on a version string
(
tests.conftest.requires_nttagg), so the suite stays green on the released 1.0.1 the pin still admits. - Two hard-coded kind lists in
tests/test_examples.pywidened, ungated. The second one was already red against the library's newExactDiceOfDiceentry; the plan had identified only the first. - [NTT-Accuracy], carried forward to the backlog: the accuracy exhibit that would show what makes the kind interesting.
-
-
[Release-1.0.0] DONE (
1.0.0), plandev/done/plan-1.0.0-release.md. The first public release, timed with the library's 1.0.1 on 2026-10-07. Three packaging defects meant no installation route delivered a working app, and all three were invisible to both suites because both read the working tree in place. Detail inCHANGELOG.md1.0.0.-
[tool.uv.sources]removed,aggregate>=1.0.1,<2pinned. The table was fatal touv pip install git+..., not merely unhelpful: uv honors it for a git-installed project and looked for the sibling worktree inside the repo. -
package-datacarriesstatic/assets/*. Apackage_dataglob does not recurse, so the wheel shippedindex.htmland none of the thirteen files it loads: 200 for/, 404 for every asset. -
scripts/release-check.ps1, the rehearsal that found all of it. Builds, inspects the wheel, installs into a clean environment, runs the suite against the installed package, serves the app and fetches every asset. -
test_health_needs_no_thread_tokenstopped walkingapp.routes, which FastAPI 0.142 no longer flattens, so it passed on the locked pins and failed on the ones a fresh install resolves.tests/test_packaging.pyadded. - PyPI metadata,
Development Status :: 4 - Beta, README install section rewritten aroundpip install aggregate_api. - Author's, not yet done:
uv publish,git tag -a v1.0.0(this repo has no tags at all), the GitHub release with the distributions attached. SeeV:\dev\RELEASE-PROCESS.md.
-
-
[Punch-List-Oct-07] DONE (
1.0.0a198to1.0.0a200), plandev/done/plan-a198-punch-list.mdwith its execution notes beside it. The author's 2026-10-07 punch list after kicking the a197 tires: six items landing as five version bumps across three repositories, all executed 2026-10-07.-
1.0.0a198[quick-re], the five faults in the Quick Re quote sheet: the table cycles with the page's table view off a table document, the minimum rate on line becomes the fourth candidate sobindsnames it, a row carries its layer name beside its span, a rate on line is written as a bare fraction and rounded to four figures so the clause and the sheet agree to the digit, and an occurrence tower stops at the policy limit.policy_limitjoins the build response. Detail inCHANGELOG.mda198. -
1.0.0a199[narrative-bounds],white-space: pre-wrapon the narrative panes, and the Bounds form on a P&L seeding off the closing block rather than the gross one.net_premiumjoins the preview response and all three premium figures are named wherever the pair was. Detail inCHANGELOG.mda199. - library
1.0.0a397and plugin0.9.0[pnl-emphasis], PnL Summary and Waterfall bolding gross, each net of tier and the closing net, andwaterfall_df'sCRbecomingMargin ratio. The plan named plugin0.8.0, which [Waterfall-Capital-Catchup] had already taken, so it landed as0.9.0. - library
1.0.0a398[reins-labels], the Reinsurance plot's annual triple namedGross,Ceded to occurrence,Net of occurrence. The document-wide legend strip goes from three chips to six, which the plan anticipated; the revert is one line if that reads worse in use. - library
1.0.0a399and api1.0.0a200[capstone],Capstone.PCreplaced in place byCapstone.Capped, a capped quota share that peels top-down. Detail inCHANGELOG.mda200.
-
-
[PnL-Pentagon] DONE (
1.0.0a195,1.0.0a196), plandev/done/plan-a195-pnl-pentagon.md: the PnL group gains a Pentagon leaf drawing gross, ceded and net as one figure, at a solvency level picked from a strip of six mini pentagons.a195is the api half (thePOST /v1/objects/{id}/pnl/pentagonroute serving one frame per level, thecan_pnl_pentagonflag, the runner in its ownaggregate_api/pnl.py);a196is the figure, ported fromaggregate-asp, with its level strip and its note. Librarya392([Delta-Row-Marked], the stitched impact row stops printing a negative standard deviation) anda393([PnL-Pentagon],PnL.pentagon_df). Not in this plan, after the author's ruling at review: the Waterfall leaf gaining the same strip, which needs the library's conditional capital bases parametrized offPERCENTILE_LADDERfirst and is its own upstream plan. See the plan's execution log for the five other divergences. -
[PnL-Exhibits] DONE (
1.0.0a194), plandev/done/plan-a194-pnl-exhibits.md: the Overview group becomes uniformly the wrapped book and the PnL group uniformly the ledger, which gains a Tail leaf for the closing margin's ladder. PnL Summary draws one table read across a row, PnL Waterfall's second table is three capital bases with the cost of each (every capital figure the negative of a193's, reading as capital rather than as the margin in the bad state), and PnL Ledger inheritsSkew. The P&L summary card loses its leaf; nothing it carried is unreachable. Librarya388-a391([Overview-Engine], [PnL-Summary-One-Table], [Waterfall-Capital], [Ledger-Skew]).check-nav.mjs'sEXPECTEDtable brought current, having fallen eleven findings behind the library. Detail inCHANGELOG.mda194 and the four library entries. Next: a195, the PnL pentagon, which depends on this bump's column rename. -
[Tower-Generator] DONE (
1.0.0a193), plandev/done/plan-a193-quick-re-tower.md: the Quick Re row takes a second button, Tower, that lays one span out as a stack of quote-sheet-rounded layers with a climbing placement ladder, names themOcc 1up, and cedes the stack as one clause. Reverses the row's own "ONE layer, deliberately" ruling, on the author's reversal of 2026-10-06. The arithmetic is newweb/src/tower.js, ported fromaggregate-aspexcept for the ladder, which aSP walks downward. The attachment box now reads a bare0, which Add re gains too. SPA only, no library change. Detail inCHANGELOG.mda193. -
[Decl-Parse] DONE (
1.0.0a192), plandev/done/plan-a192-decl-parse.md:POST /v1/decl/parsereturns the(kind, name, spec)triple the parser understood, one entry per statement, building nothing and caching nothing. Requested byaggregate-aspfor its[Program-Import]step, which reads the structure of a pasted program rather than regexing it out ofpprogram. A non-finite float in a spec serializes as"inf"/"-inf"/"nan"through the newserializers.spec_to_payload, and a parse failure is the existingErrorReport422 plus astatement_index. Detail inCHANGELOG.mda192. -
[Punch-List] DONE (
1.0.0a191), the author's 2026-10-01 punch list: the rate menu items light (upstreampnl_program(premium_style=)shipped as library a386), the net-of-occurrence subtotal reaches PnL Summary, Waterfall and Lab Relativity (library a387, plugin 0.7.0), Insurer Summary drops the by-leg table, the Waterfall gainsMargin ratio, Bounds auto-computes on a P&L at the ledger premium, and the Pricing Bounds heading names the base constraint. Detail inCHANGELOG.mda191 and the two library entries. -
[Evaluate-Targets] DONE (
1.0.0a190), author's tweak after kicking the a186 tires: Evaluate offers the full CoC | LR | Premium switch (it passedtargets: ['premium']and drew a bare label), a CoC or LR resolving its premium through the pentagon at the anchor before evaluating; a typed Premium stays gross of expenses, and the help is the author's sentence verbatim. -
[Expenses] DONE (
1.0.0a186), plandev/plan-a182-pricing-pnl-forms.mdpart [expenses]:expense_ratioon the four pricing request bodies (a premium target reads as gross, the engine runs on its technical part, the arithmetic in the runners once), the preview'sgross_premium/net_of_expense_premiumpair, the shared expense box on Calibrate, Allocate and Evaluate, and the P&L ledger pair on the Bounds preview and the dormant Evaluate band. This closes the plan's four parts (a182, a183, a184, a186; a185 was the unrelated matrix fix); the plan stays indev/until the author calls it done. The rate menu items lit at a191, when the upstreampremium_styleask shipped as library a386. -
[Sentence-Forms] DONE (
1.0.0a184), plandev/plan-a182-pricing-pnl-forms.mdpart [sentence-forms]: the five pricing form mounts read as one sentence each in the Quick Re idiom, the band label and◦spacer retired, and a?per form carries the explanation. Visual acceptance (all six states, phone wrap) awaits the author's browser pass. -
[PnL-Dropdown] DONE (
1.0.0a183), plandev/plan-a182-pricing-pnl-forms.mdpart [pnl-dropdown]: the PnL split button with fixed labels (PnL, and a caret with PnL (rate), xPnL, xPnL (rate)), the stale-object reset bug fixed by deriving from the box,formandpremium_styleon the pnl route, and thecan_pnl_rate/can_xpnlflags. The two rate items stayed dark until the upstream ask shipped (pnl_program(premium_style=), library a386); the api feature-detects the signature, so the a191 sync lit them with no change here. -
[Evaluate-Auto] DONE (
1.0.0a182), plandev/plan-a182-pricing-pnl-forms.mdpart [evaluate-auto]: Pricing / Evaluate on a P&L computes on arrival and the form band goes dormant (drawn, dead, explained) rather than hiding its field pairs. The plan's remaining parts ([pnl-dropdown], [sentence-forms], [expenses]) land as a183 onward; the plan stays indev/until the author calls it done. -
[Matrix-Legibility] DONE (
1.0.0a181), plandev/plan-a179-lab-tab.mdsection 9: the matrix is acustomseries with pixel band gaps and its own height, row names wrap, an empty axis label draws no name, and an ordinalxyaxis readsChartAxis.categoriesand draws as a trend. From the author's review of the first Lab render. -
[Matrix-Renderer] DONE (
1.0.0a180), plandev/plan-a179-lab-tab.mdsection 8: the ECharts adapter reads chart IR version 4 and draws thematrixpanel kind. Required for any build running librarya379or later, since the adapter's version check is one-sided and an unraised pin blanks every chart. -
[Lab-Tab] DONE (
1.0.0a179), plandev/plan-a179-lab-tab.md: third-party charts and exhibits appear under a new Lab tab, discovered throughaggregate.pluginsentry points.AGGAPI_PLUGINS_ENABLED/AGGAPI_PLUGINS_ALLOW, the manifest onGET /v1/meta, a dynamic seventh nav group, one genericlab:*loader.capability.pydeliberately untouched; see the plan's section 5. Verified againstaggregate-relativity0.1.0, which is not a dependency of this repo and must not become one.
The author's plan, set out 2026-07-31 (Friday), to finish over the weekend. Each
becomes its own dev/plan-*.md and its own version bump.
The connector arrived while this was being planned. GT 1.8.0 shipped
irToGridInput(doc), 1.9.0 renamed the package back to greater_tables, and
both landed: a34 the rename, a35 the single fetch. Every table under 500 rows is
now switchable off one document, the densities stay on the bulk path, and the
stats_df divergence that a33 introduced is fixed and guarded.
The switch did not move. It is still in the header menu, deliberately: where it belongs depends on (c), so settle that first. The argument recorded last time still stands, and is now cheaper to act on: the flip costs no round trip, which is a point in favor of putting it back next to the table.
Left over from this work:
- Look at the tables. Still nobody has seen one in the page, and there is now more to look at: 1.7.x spanner rules, and an interactive view whose numbers arrive as raw values with IR-declared formats rather than pre-rounded off the wire. Build a portfolio, then walk Overview, More, Reins and Price flipping the switch on each.
- Upstream, reported:
include_raw='data'andirToGridInputdo not compose.'data'covers numeric, date and bool columns only, so a string data column gets no raw value and the adapter then throws on the whole document. Three Price frames carry one. We pass the explicit column list instead. Written up inc:/s/ai/greatest-tables/dev/note-from-aggregate-api-include-raw.md. - Two harnesses in
dev/scripts/:check-frames.py(every frame, every kind, both routes agree) andcheck-adapter.py(a document is interchangeable with itsFrameResponse). Run both whengreater-tablesmoves. A third joined at a39:check-exhibits.py(every exhibit, every kind: capability and envelope agree, byte determinism, insurer blocks match the frame routes row for row). A fourth at a44, and it is the app side rather than the server:capture-capability.pywrites one build response per kind todev/fixtures/capability.json, thennode dev/scripts/check-nav.mjsruns the real rules fromweb/src/nav.jsover them and prints a leaf-by-kind grid. Run it whenever a leaf, a gate or a library registration moves.
The [Exhibits-App-Endpoint] phase of the library's dev/plan-exhibits.md
landed its additive slice at a39: the capability and envelope routes plus
check-exhibits.py. Still open, gated on the library's PnL insurer framing
review: the menu-from-capability rewrite (applyKindGating and the
hardcoded NA tables read the capability response; has_reins gating folds
in; chips gray out, never hide; unknown-to-the-page exhibits list under
More), deleting the migrated ROW_FLAGS / FORMATS entries and the
main.js title and caption literals (pricing FORMATS were to stay; as of
2026-08-12 they delete too, per dev/plan-pricing-exhibits.md), wiring
check-exhibits.py into CI, and extending capture_fixtures.py to the
envelopes. (The name collision that blocked the last of those is
settled: a62 renamed the chart fixtures to dev/fixtures/charts.json,
so exhibits.json is free for the library's exhibit envelopes.) The
[Exhibits-App-Cleanup] decision (retire _drop_raw_moments by
re-pointing the frame routes at exhibit raw and insurer, or keep the frame
routes as the raw CSV path forever) is taken during the endpoint phase
proper.
Settled at a71: every table the library publishes is drawn as published.
Twelve of the nineteen table leaves take the exhibit route, which is all of them
that can. ROW_FLAGS is empty and FORMATS holds only frames no exhibit
serves. The [Exhibits-App-Cleanup] decision above is therefore taken: the
migrated entries are deleted, and the frame routes stay as the raw / CSV api
path, rendered by inference.
What is left, and none of it is a published table: Bounds (stays with the
library's dev/plan-exhibit-official-channels.md phase 10, the one open item
of that plan), and the two densities, bulk and the one exception the
author scoped out. More Sharpen closed at a94: loadSharpenAudit became
loadExhibitLeaf on the a255 sharpen exhibit, the two block ledes went
with it, and tables.FORMATS is empty. Pricing closed at a83 to a85 via
dev/plan-pricing-exhibits.md (three subtabs served by three exhibits on
result objects, [Pricing-Keyed-On-Result]). The asks were written up as
aggregate_REFACTOR/dev/note-from-aggregate-api-round-6.md; items 1, 2, 3, 5
and 6 closed upstream at a251 to a256, and item 4 closed through the pricing
plan.
Most of the way (a36, a37). a36 took the Plotly path out: engine.js,
plotly-panels.js, the draw control, the dependency and the 535 kB chunk.
twoPanelData stayed.
a37 did item 5 of the a30 graph notes, the horizontal y-to-x readout, plus three
things the first browser look turned up: full x widening only one panel, the
return period capped at 1e5, and densities drawing as pyramids rather than steps.
Superseded, 2026-08-09, by dev/plan-plot-ir-api.md. Configuring ECharts
turned out to be the smaller half. The author's ruling is that the app assumes
IR-based charts always, and purist about it, so the open items from the a30 graph
notes moved into that plan (item 7) alongside the chart-rendering items from
dev/api-punchlist.md, and they are done as part of the migration rather than
against the app's own builders. dev/graphs.md was deleted once its content
landed there. The plan also carries the deletion of the server-rendered
matplotlib route and the adoption of the four converted emitters.
Most of that plan landed at a62: the 2-D adapter, all seven documents
adopted, the purist availability rule, and the control strip off the document.
exhibits.js is gone. What is left of it is item 7's remaining punch items
(7.1 zoom disorientation, 7.2 double-click reset, 7.4 the readout in the
legend) and the heatmap declaration upstream.
Every chart on the page is a different picture now and nobody has seen one.
Ten documents replay clean through the real adapter in node
(dev/scripts/smoke-charts.mjs), which proves they reach the renderer in a
drawable shape and that each declared reading changes the drawing. It proves
nothing about how any of them looks. Worth one browser pass, and there is more
to look at than usual: a portfolio now draws a kappa panel instead of an
exceedance panel, a P&L carries break-even marks in both panels, a
bivariate draws flat and no longer square, and the four controls (log, full
range, return period, invert) are new words in a new place.
The one that decides whether the rest was worth doing, and the least specified. Feeds back into (a): the switch cannot find its home until the tabs settle.
Reviewing this is what --library (a36) is for: point the server at a short
.agg and the dropdown and hero gallery narrow to it, so a pass over the tabs
is not a walk through 186 recipes.
uv run aggregate-api --port 8001 --library T:\tmp\short.agg
Still open from before and probably part of this: the Bounds tab has no content, and the standing REMINDER below about what is worth plotting.
-
plan-loss-lab-navigation — the answer to (c), and it absorbed the Bounds item above. Seven stages, one version bump each (a42 to a46): the Loss Lab rename, the capability payload that killed
NA_TABS_BY_KINDandNA_MORE_BY_KIND, six nav groups with their own sub-tab rows, the Sharpen / PnL / Reset action row, the reinsurance entry box, Bounds, and the Narrative pane. (done; moved todev/done/)Left open by it, deliberately: the header's **Perspective** control. The plan lists it under page-wide preferences and no stage owns it, so the exhibit fetches take `insurer`, which is the plan's stated default. The Tables switch beside it is live; this one is not built. **Nobody had clicked any of it.** The gating was proved by `check-nav.mjs` against real payloads and every route has tests, but the six groups, the three derivation buttons, the cession box, the three bounds forms and the Narrative pane had never been used in a browser. The author's first pass found the Bounds group dark for every object (fixed at a48, below), and the rest of that first pass became `plan-ui-round-3`, immediately below. -
plan-ui-round-4 — the second full pass (a55 to a61, with a54 the upstream catch-up that unblocked it). Eighteen items off
dev/api-punchlist.mdRound 4, six phases: the nav and its greying; the strip's verdict and history; the strip's facts; the action row; two hamburger preferences; the cession box and Quick Re.Three of the six were the page telling the truth rather than new features. The greyed group tab had been unable to draw its own tooltip since a48, because Bootstrap's `.disabled` class carries `pointer-events: none`. A clean gross under reinsurance tinted the strip amber. A bivariate's status line said nothing but its name, because its `bs` is two numbers. And `BuildResponse.warnings` had been declared from the start and never filled. **a60 was not in the plan.** Upstream removed the `plot_envelope` keyword the api was passing, and rather than repair a route already marked for deletion the author's call was to take matplotlib out: the envelope is a chart document now, drawn by a new 2-D path in the adapter, and `plotting.py` and the `/plot` route are gone. That is `plan-plot-ir-api.md` item 1 and the bounds half of item 5, landed early. *(done; move the plan to `dev/done/` once the browser pass below is made)* **Nobody has looked at any of it.** Every phase is proved by tests, `check-nav.mjs` and a node run of the adapter over real documents, and not one of the six has been seen in a browser. Worth one pass: a `grossceded` object for the tooltips, a bivariate for the status line, a reinsured aggregate for the green verdict and Quick Re, and the Bounds envelope for the new 2-D chart. -
plan-ui-round-3 — the first full pass over the running site (a49 to a52). Roughly forty items off the author's punch list, taken after the first end-to-end run. Four phases: the shell and the status strip; the charts; the text and the tables; the reinsurance and pricing forms. (phases 1 to 4 done; the doc stays in
dev/until phase 5 lands)**Phase 5 is not done and is blocked**, on `aggregate_REFACTOR/dev/plan-loss-lab-round-3.md` phase A, which has not started. Four items wait on it: - `evaluate`, gross / net occurrence / net on the Evaluate form, which needs the library's basis keyword rather than more of the `_BasisView` shim. - `alloc`, the per-unit allocation tables a reinsured portfolio silently loses, same keyword. - ~~`cession`, pricing a cession with a distortion; the library has no glue between reinsurance and distortions at all.~~ **Done at a197**, `dev/done/plan-a197-layer-pricing.md`. The glue arrived in the meantime and then turned out not to be needed: `Aggregate.reins_price_df` prices gross / ceded / net and not the layers, so the quote distorts each layer's own annual distribution, reached by building the one-layer `ceded to` program `reins_program` renders. Quick Re now writes a `deposit` or a `rol` on every layer it cedes. - ~~`replot`, the Reinsurance Plot leaf on a reinsured **portfolio**, which greys because `chart_reins` is registered for `Aggregate` alone.~~ **Answered, not fixed.** Library a244 rewrote `chart_reins` as the occurrence plot and states the restriction as the author's decision for 1.0: a book's units cede on different stages, so a portfolio-level gross / ceded / net triple would have to pretend they cede on the same one, and the aggregate cover is a separate contract with a separate picture. The leaf is dark there on purpose and `nav.js` says so. Two things the round turned up that are the library's and are recorded here rather than acted on: - `plot_envelope(distortions='space')` is a documented value that does nothing: it matches neither of the overlay branches, so panels 2 and 3 draw empty. a52 stopped asking for it and builds the list itself. - `format_program(width=)` is accepted and ignored, which is the agg plan's `width` item.
- Bandwidth limited by caddy page with obscured url; special caddy install
(done —
rate_limiton the public/Q7M4Z9KProute, build-only, plus a friendly 429 card; see human-hints.) - Set up service to run on vps (done 2026-10-20: the systemd unit in
human-hints, with
AGGAPI_CACHE_MAX=100;refresh.shrestarts it) - Limit log2 <= 18 (
AGGAPI_LOG2_CAPdefaults to 18) - [ ]
-
[Excel-Info]
AGG.INFO(handle), first class. The object'sinfotext (GET /v1/objects/{id}/info, whatAggregate.infoprints and the Lab's Narrative leaf shows) has no function; it is the first thing a reader wants of a handle and it belongs besideAGG.EXHIBITS. Returns the text as one cell, newlines kept, likeAGG.PROGRAM; a program in place of the handle builds first, as everywhere. Author's ask, 2026-10-17, after the 1.26.0 tire kicking in Excel on the web. Ideas raised the same evening, unruled: an Insert button beside each Copy in the pane's Whole frames section, writing the text into the selected cell; a library picker in the pane writing=AGG.LIBRARY("…"); a Store listing ([Excel-Store], below). -
[Excel-Store] list the add-in on the Microsoft Marketplace. REJECTED 2026-10-28 (author: "never going to happen"); the plan is closed as
dev/done/plan-excel-store-REJECTED.md. The entry as it stood: the one-click install for everyone (STORE tab in desktop and web Excel plus Microsoft's installation link). Author's ask, 2026-10-18, after the desktop install proved to need a shared folder and a Trust Center edit (dev/excel-desktop-install.mdhas the recipe). Plan:dev/done/plan-excel-store-REJECTED.md, rulings D1 to D6 made 2026-10-18 (Convex Risk publishes, "Aggregate Loss Distributions", help@convexrisk.com, own terms page, 90-day audit pruning, a friend's Mac withdev/store/mac-test-guide.md). Partner Center enrollment needs a work account (the convexrisk tenant) and has the longest lead time, so it starts now. The Caddy limits are live (verified 2026-10-18), and the VPS runs under a systemd unit withAGGAPI_CACHE_MAX=100(2026-10-20). Interim for colleagues in a tenant: an admin's Integrated apps upload, no client setup at all. 2026-10-18: enrollment stuck (Partner Center will not validate the author's email), so the listing may not happen. [server-ready], [store-pages], [audit-retention] and [tenant-deploy] go ahead regardless; [store-pages] now puts help, privacy and terms at the site root, for the whole service including[Sheets-Template]. -
[Build-Single-Flight] identical builds arriving together build once. A request waiting on the build slot never re-checks the cache, and the store happens after the slot is released, so twenty simultaneous POSTs of one new program run twenty serial builds. Excel hides it with its client-side in-flight map; Sheets cannot. Landed as 1.26.1 (
dev/done/plan-build-single-flight.md): the waiter re-checks under the slot, the store moved inside it, and/v1/statusreportscoalesced. -
[Quantiles-LEV] the quantiles route reports the limited expected loss,
P(X ∧ q(p)), beside each quantile on the aggregate basis, for aSP's default haircut ([Loss-Input-Pricing]). Landed as 1.28.0 (dev/done/plan-quantiles-lev.md):levis the library'sprob_loss_assets(a=q).Lon the lawqread, null on the occurrence basis. -
[Front-End-Apps] serve other front ends at
/<name>/, each from its own repository, named inAGGAPI_APPS(asp=<folder>), with an Apps menu in the playground built from/v1/meta; adding one is an entry and a restart. First tenant: aSP at/asp/, whose half is[Serve-From-aLL]inV:/dev/aggregate-asp. Also stops the playground's service worker caching anything outside its own files, and shortens the All rows menu item. Author's ask, 2026-10-18, ruled to land before[Sheets-Template]. Landed as 1.27.0 (dev/done/plan-front-end-apps.md);/<name>needed an explicit redirect, since the SPA's/mount shadows Starlette's own. -
[Sheets-Template] the AGG functions in Google Sheets, as a script bound to a template spreadsheet shared by a
/copylink (AGG_BUILDand the rest, one sharedcore.ts, a Recalculate menu item, whole frames throughIMPORTDATA). Author's ask, 2026-10-18; rulings D1 to D6 the same day. Plan:dev/done/plan-sheets-template.md. The spike passed; the code landed as 1.29.0 (sheets/), and the copy link as 1.31.1, inREADME.md,sheets/README.mdandSHEETS_TEMPLATE_URL, held together by a test. Still to run, the author's: push the script, runaggSetUpTemplatekeeping Sheet1 blank, share the template (steps 4 to 6,sheets/README.md), and the template acceptance. A Marketplace editor add-on follows only if it gets traction. -
[Use-Page] a page on running
aggregatefrom Jupyter, R, Excel and Sheets, at/usewith deep links (/use#r,#excel-desktop), from Menu ▸ Using in Jupyter, R, Excel, Sheets. Four folder tabs of steps the reader ticks off, each beside a drawing of the result, all on one program whose quantiles a test checks. Author's ask, 2026-10-19, for the R demonstration on 2026-10-20. Landed as 1.31.0 (dev/done/plan-use-page.md, specdev/prototypes/use-page/side-by-side.html), with greater-tables 7.0 and a fix for the Lab dying when the browser blocks site data. -
[Lite-Shell] [Lite-Reading] the phone lite entry (
dev/done/plan-phone-lite.md, specdev/prototypes/phone.html), a168 to a169, for the 2026-10-16 live demonstration. One URL: a boot-time branch inindex.htmlsends a narrow, coarse-pointer device tolite.html, a read-mostly showcase (curated chips, read-only program, Build, facts, tiles, one chart, one static table, the example sheet);?full=1/?lite=1override. The full app is untouched beyond the branch script and a second Vite input.- [Lite-Device] the author's hour on a real phone before 2026-10-16; findings become ordinary tweak bumps (a170 on).
-
GUI round 9, five punch-ups from kicking round 8's tires (
dev/plan-ui-round-9.md), a159 onward, from an author report on the running app. Two of the five were bugs with proven causes; three were rulings. The author's sixth item, the chart control strip, is deferred to its own plan and is summarized in this one's "Out of scope".- Phase 1 [Strip-Fold], a159. a158's note slot was unreachable: the
chevron that opens it was hidden by a
display: nonein its own rule and revealed withmore.style.display = '', which clears an inline value rather than setting one. Build warnings, derivation sentences, tags andnote{}were all on the page and none could be opened. This is also what round 8's unwalked acceptance states would have caught. - Phase 2 [Grid-Formats], a160. The interactive view throws on any
gformat spec, which is whatgreater_tablesemits for a "general" column: six of the twelve exhibit blocks a portfolio publishes, not the one that was reported. Fixed upstream incsv-viewer3.10.0 (its owndev/plan-3.10-g-format.md). a160 lands the honest failure message, which the pane never gave, and a secondcheck-adapterpass that names every unparseable spec.- The pin moved, a163, once CSV_Viewer was pushed and
csv-grid 3.10.1 was on PyPI for the server-side consumers.
check-adapternow reportscsv-grid 3.10.1 takes [fd%esg]and passes its spec pass clean, and the six exhibit blocks that drew nothing draw again. - Upstream, found while walking every exhibit:
bs_windowis listed byavailable_exhibitsfor an object that cannot produce one (this portfolio atlog2=12, bs=1), andbuild_exhibitthen dies on a None frame inaggregate/_labeled.pyinstead of raising something the route turns into a 400. The frame route declines the same object cleanly with a 400.
- The pin moved, a163, once CSV_Viewer was pushed and
csv-grid 3.10.1 was on PyPI for the server-side consumers.
- Phase 3 [Three-Rulings], a161. More leads with Tail behavior instead of the heavy Density load; Quick Re's refusal names the two amounts that collide instead of restating a rule; the control band takes the editor's white ground rather than the status strip's tint.
- Item 1, the chart control strip, its own plan
(
dev/plan-chart-controls.md), a164 onward. Three unenclosed rows stand above every canvas and.exhibit-group-panel's equal-share centering promises an alignment to the panels it cannot keep.-
[scope], a164. The four grid rendering controls and the cut become panel controls, since what they change is one panel's drawing.lightsstays in the figure box by the author's ruling. -
[align] [below] [box] [short] [fold] [trim] [stack] [tone], a165, the arrangement: everything below the drawing, panel groups at their own columns, the figure box at the drawing's width. Acceptance 1 to 6 are a browser walk and are still to be kicked; the plan's "Execution notes" carry the divergences.
-
- Phase 1 [Strip-Fold], a159. a158's note slot was unreachable: the
chevron that opens it was hidden by a
-
GUI round 8, where the dividing lines lie (
dev/done/plan-ui-round-8.md), a157 to a158, from an author report that the design is good but a lot "floats about" and that the status strip gets glazed over. Four rulings taken at review time and eleven divergences are in the plan's "Execution notes" section. The five visual states in the phase 2 acceptance list still want walking in the running app: no suite here exercisesrenderSummaryorsyncSummaryMore.- Phase 1 [Rhythm-And-The-Control-Band], a157. Three spacing tokens
replacing a page of local margins, one enclosure on the form row with
its explaining line gathered inside it, and a name on the Pricing and
Bounds bands. The largest divergence: the plan's
:has(+ .control-band)selector reached only Bounds, since Pricing nests its forms in#leaf-*wrappers and Re puts its program lede in between. - Phase 2 [The-Status-Strip], a158. Clusters instead of seven
·separators, the verdict said only when it is not clean, the clock in the corner instead of a sentence on a line of its own, and the note slot folded behind a chevron that carries the warning count. The chevron had been dormant since it was added: it was shown only when line one overflowed horizontally, which a freely wrapping line cannot.
- Phase 1 [Rhythm-And-The-Control-Band], a157. Three spacing tokens
replacing a page of local margins, one enclosure on the form row with
its explaining line gathered inside it, and a name on the Pricing and
Bounds bands. The largest divergence: the plan's
-
[Examples-Search] the doubled list and the alphabetized ties, from an author report, a139. Searching
capstonedrew the eleven hits twice and in alphabetical order. Two independent faults.renderListpublished the search needle from between itsemptyand its firstappendChild, so the fanout re-entered the calling surface's own render and the outer pass appended everything again; publishing moves topublishNeedleon the boxes'inputhandlers and the render is a pure draw. And uFuzzy's default sort ends in a locale compare, which decided the whole list for a query that scored all eleven identically; the tiebreak is the haystack index now, which is the position inlibrary.agg. Ranking above the tail is untouched. The Ctrl+Shift ring inherits both, so a family search walks the worked example in the order it is built. -
GUI round 7, August 27 (
dev/done/plan-ui-round-7.md), four items at a138, from an author list of six. The editor wraps; the Economics tab becomes PnL (label only, theeconomicskey stays);collapse_programruns the library'spreprocessso a#or//comment stops swallowing the program behind it, with an empty or comments-only program answered in its own words; and thedata-whyfootnote moves out of the width ghost's::afteronto a node of its own, so a dark tab no longer narrows on hover. Arithmetic joined the first of those: DecL'sanswerrule has always carriedexpr, so(2+2)is a program, and the api now serves the float askind: 'value'rather than building it and refusing it. Two of the six needed no code here. The bivariate program the author asked about is correct (no-frequency production, Poisson by default), but checking it found thatformat_programdropsnote{}andtags{}on every program, now an upstream ask below. On the SpaceMouse the settings match the testbed exactly and the load does not: 65,536 vertices against the lab's 9,216, plus a fullsetOptionmerge per frame. Two levers, both in the plan's last section, neither pulled yet. -
Punchups, August 24 (
dev/done/plan-punchups-aug-24-API.md), all ten live items, a125 to a133. The author's eleven item list, item 2 withdrawn the same day. One item per bump except 6 and 7, which are one edit, and item 10, whose four sub-items landed together. The author's numbering is kept, gap included, because that is how the items got named in conversation. Execution notes and every divergence are in the plan's own "Execution notes" section.- 1 [Example-Load-Strips-Trailer] a picked entry loses
note{}andtags{}, and the strip prints the note off the item's own fields (→ 1.0.0a132).hints{}stays. -
2withdrawn 2026-08-24: units of aportor abivariateare not entries, and nothing is owed upstream. - 3 [Editor-Margin-Controls] the walk buttons align right and lose their boxes (→ 1.0.0a127). Circled arrows, bare, at the icon's size.
- 4 [Clear-Twice-Clears-History] a second press of the clear icon empties the store (→ 1.0.0a128). No dialog; the readout says "cleared".
- 5 [Example-Ring-Follows-Search] the ring follows the search box as well as the pills (→ 1.0.0a133). The pill half had landed with the examples dropdown work; the search needle was what was left.
- 6 [Stats-Joins-Overview] and 7 [Overview-Leaf-Order] (→ 1.0.0a125). One edit: Stats moves from More to Overview and the row reads Plot, Summary, Validation, Stats, Tail.
- 8 [Reformat-Keeps-Trailer] Reformat stops deleting the note and the
hints (→ 1.0.0a126).
trailer=True, and tags come back with them. - 9 [Tooltips-Stay-On-Screen] the
data-whyfootnote clamps to the viewport (→ 1.0.0a130).utils/tip.jswrites--tip-shift. - 10 [Surface-Strip-Punchups] four fixes to the 3-D control strip (→ 1.0.0a131), all four in one bump. The Download menu carries PNG and is drawn on every chart, so "Download plot" leaves the header menu.
- 11 [Counter-Follows-The-Example-Walk] the
[m/n]readout numbers the example walk (→ 1.0.0a129). The counter follows the last press; the two buttons stay bound to history.
- 1 [Example-Load-Strips-Trailer] a picked entry loses
-
Bounds was dark for every object (→ 1.0.0a48).
can_boundsandcan_allocatereached the browser and were never copied onto the flags the rules read, so the group greyed everywhere whilecheck-nav.mjspassed: the checker calledcapsFromResponseand the app hand-rolled its own equivalent. The app now uses that one function, so the two cannot drift again. Found on the first browser pass, which is the note above earning its place. -
plan-revamp-aug-06 — the shell revamp (→ 1.0.0a47). One type scale replacing twenty sizes, the press ramp with the house red as the accent and blue gone, real folder tabs over a small caps sub menu, one action row and one status strip, a merged title-and-gloss line per exhibit, greyed items that say why on hover, and keyboard navigation over both strips.
site.cssfully tokenized on the way through. Designed inhacks/mockup-10-concepts.html. Follow-up, still Bootstrap-colored:gt.css,csv-grid.cssand the ECharts palette incharts/theme.js. (done; moved todev/done/) -
plan-0001 — bootstrap standalone (→ 1.0.0a2). Make the extracted code import, run, and pass tests as
aggregate_api. Wire theaggregateeditable source. (done; moved todev/done/) -
plan-ui-enhancements — SPA editor fix & redesign (→ 1.0.0a3). Tamed autocomplete, emacs keys, archivum look-and-feel, tabbed output, native plot + reins / CSV endpoints. (done; moved to
dev/done/) -
plan-0002 — UI tweaks, bug fixes, a4 enhancements (core → 1.0.0a4). Editor fixes, tab reorg + More dropdown, phone-fit, Density + bs-window panes, format_program on examples, curated-examples env knob, Price pentagon + distortion analysis, friendly 429, bs + timing in the summary. Survivors dispersed: C1 + D2 →
plan-misc-01; D1 superseded byplan-grid(CsvGrid filters); E is upstream (aggregate.mplstyle). (done; moved todev/done/) -
plan-misc-01 — p=1 pricing, friendly 422s, standalone Distortions (→ 1.0.0a9). Relaxed
PriceRequest.pto(0,1]; FastAPI validationdetailarrays now render as"<field>: <msg>";dist …builds askind="distortion"with Info/Describe/Stats/Density/Plot (absorbs plan-0002 C1);hints{ log2=N }now counts againstAGGAPI_LOG2_CAP(absorbs plan-0002 D2); csv-grid version shown in the header. (done; moved todev/done/) -
plan-misc-02 — assorted playground tweaks (→ 1.0.0a10). Six small fixes: build-time semantic errors (unknown distortion kind) return a clean 422 (unwrap
VisitError) not a 500;MultivariateAggregate(multivariate/mv/netceded) builds askind="multivariate"; input newlines/tabs/\collapse so multi-line programs build; Stats/Reins-stats omit raw-moment rows (ex1/2/3); Price defaults CoC 0.15 / LR 0.90; density / reins-density / kappa bin to a faithful 2¹¹ power-of-two display grid. House rule: tabs grey out (disabled), never hide — retrofits plan-misc-01 C. (done; moved todev/done/) -
plan-0003 — dev workflow & smoke test (later). Document/verify the end-to-end loop:
uv run aggregate-api --reload+npm run dev, build the SPA, hit/docs, build an object in the playground. Add aruffpass. -
plan-help — short in-SPA help (→ 1.0.0a5). Always-visible top-right
?opens a compact offcanvas (one-liner, try-it + Load it, keys, controls + tab guide, links, fair-use note). (done; moved todev/done/) -
plan-grid — adopt CsvGrid for table output (→ 1.0.0a7). Every SPA table now renders through
csv-grid(sort / fzf search / per-column filters); per-pane chrome, per-column Price formats, destroy lifecycle, dead-code sweep (actions.js/pricing-pane.js/plot-pane.js/.tbl/ stalepublic/index.html). Density preview lifted to 2 000 rows. (done; moved todev/done/) -
plan-ui-enhancements-01 — small UI polish (→ 1.0.0a5). Phone-friendly form inputs: 16px on mobile (no iOS zoom) +
autocomplete=off(no AutoFill bar) for the Price inputs and the custom-bs input. (done; moved todev/done/) -
plan-pwa — installable PWA + retire the obscured prefix (Phase B → 1.0.0a6; Phase A VPS cutover 2026-06-13). PWA manifest +
sw.js; app moved to theagg.mynl.comsubdomain (same-origin, auto-TLS, explicit/docs404, build rate-limit);human-hints.mdrunbook rewritten. (done; moved todev/done/) -
plan-envelope-band-render, the bounds envelope band draws in the wrong place. The adapter realized the document's
y2band as an ECharts stacked pair, and stacking on twin value axes sums the x coordinates, so the upper half drew at doubled x with the raw gap as y (the wavy 0.2 line) and the fill painted the triangle under the diagonal. Served document verified correct; broken since a62. Fixed at a99 with acustompolygon plus two plain edge lines, and the smoke test gainedcheckBands. (done; moved todev/done/) -
[Keyword-Mirror-Gaps]
web/src/decl-keywords.jsonlacksdeposit,rol,cede,reinstatements,lr,dist,bivariate,clash,grossnet,ssevandpicks, found by the library while writing the DecL help (2026-10-13). Check the whole mirror againstparser_errors._TERMINAL_LABELS, not just these. Closed at 1.30.0 by[DecL-Word-List](dev/done/plan-decl-word-list.md): the hand mirror is gone, and the editor colors fromweb/src/decl-words.json, generated fromaggregate.decl_wordsand held to it by a drift test. -
[Name-Underscore-Comment] the comment at
web/src/decl-mode.jsline 31 says names may not contain_, which the grammar allows. Fix the comment, and the highlighter's name pattern if it follows the comment. Closed at 1.30.0: only the comment was wrong (the pattern already allowed_); corrected where the tokenizer now lives,web/src/decl-tokens.js.
- CI: GitHub Actions running
uv run pyteston the private repo. - Decide the canonical
aggregatedependency story: editable local path for dev vs. a pinned version once the1.0.0aline publishes. (Decided at 1.42.0,[API-Editable-Aggregate-Source]: editable through[tool.uv.sources], a floor of what the code needs, no ceiling.) - Packaging (was "Plan E"): rebuild the SPA before
uv buildso the wheel ships the bundle; confirmstatic/*package-data works. - Auth / rate limiting if this is ever exposed beyond localhost.
- One Underwriter per session. Raised 2026-08-05, superseded by
dev/plan-session-isolation.md(see the entry at the end of this file), which carries the design and the measurements. Kept here because the diagnosis is still the shortest statement of the problem: every named declaration a build sees is stored as aRecipeunder(kind, name)withsource='session', so one shared store accumulates every visitor's declarations for the life of the process. Two users building differentport ABCcollide, last writer wins, and the store grows unbounded. The fix is a fork per session, which also gives the session download an honest scope. - Expand the example library and DecL completion coverage.
- [NTT-Exact-Rationals], a route to an exact compound's exact
probabilities. Raised 2026-10-09 with
[nttagg-Exact-Log](1.3.0). The reduced-Fractionp_exactleftdensity_dfat library 1.2.0a7 for a property built on demand, which was the right call upstream (one gcd per bucket against a 9,976 bit denominator, 77.7 s on a 1000 x 1000 case, paid by every reader of the frame) and leaves this service with no path to the rationals at all.frame/density_df.csvcarried them through 1.2.0 and does not any more. If they are wanted, the shape is a CSV-only export off thep_exactproperty, streamed and never a JSON payload: one cell of the headline case is a 410-character fraction. Open question for the author, who may well not want it, sincep_exact_log10carries about 1e-10 relative error in the implied probability and that is finer than anything the app draws. - [NTT-Accuracy], an exhibit comparing the exact and the float answer
bucket by bucket. Raised 2026-10-09 with
[nttagg](1.1.0), which deliberately left the raw material unreachable: anAggregateNTTcarriesaccuracy_df(p_exact_float,p_fft,err,abs_err,rel_errover the full grid) andntt_audit(sizes, primes, timings, error summaries), and neither is in_CSV_FRAMES, withntt_audita Series that has no shape on the frame routes at all. The reason to wait is that this is a pane with a chart and a reading rather than a dictionary entry, and the right way in is upstream: ask the library to register the exhibit so the app lights it fromavailable_exhibitsinstead of hand-wiring a route. Until it lands, the one upstreamnttaggexample (ExactDiceOfDiceinlibrary.agg) builds an ordinary-looking aggregate that happens to be exact, with nothing on screen saying so. - Density full-frame via CsvGrid
{url}+ worker (follow-up from plan-grid). (Closed — superseded by the faithful power-of-two density binning in 1.0.0a10/a11. The server now bins to a correct 2¹¹ display grid with a faithfulp_total, so the original motivation — escape the lossy server downsample — is gone. A live "scroll the entire density" view is a possible someday-feature, but it's no longer pending work.) - Persist object cache across restarts (currently in-memory only).
- Revisit
metaversion reporting: report both theaggregate_apiversion and the underlyingaggregateversion. (done in 1.0.0a2 —health/metacarryversion+aggregate_version.) -
.aggOS file association (longer-term, pended from plan-pwa). Once the app installs as a PWA, registerfile_handlersfor.agg+ consume opens vialaunchQueue→editor.setText. Chromium-desktop only, needs the PWA installed + HTTPS; value is theoretical until there's a reason to double-click a.agginto the app. On-ramp: a plain in-page "Open file" button (<input type=file>). See the "Pended" section ofdev/plan-pwa.md. - Frontend polish: keyboard-shortcut help, sharable URLs for a DecL program. (look-and-feel redesign + emacs keys landed in 1.0.0a3; these specific items remain.)
- Flesh out the Price and More output tabs. (a4: Price = pentagon + distortion analysis; More = Stats / Density / bs-window.)
- plan-user-facing — landing "wow factor" (→ 1.0.0a13). "Description to
distribution" header + subhead, random group-A hero gallery with load-time
auto-build, the Overview tab (note + interactive uPlot density/exceedance +
summary_df/tail_dfexhibits), old tabs under More; new/tail_df+/validation_dfapi routes off the upstreamaggregate1.0.0a113 frames. (done; moved todev/done/) - plan-pnl-kind — first-class
pnlkind (→ 1.0.0a14). Picked up theaggregatea114→a145 surface (a full two-sided audit; almost all internal / generic).build()now returns aPnLforpnl/xpnl; classify →"pnl", guard +BuildResponse.kindLiteral widened, density synthesized from the grand-result grid (dictdensity_df), mean/cv +construction_explanationfallbacks,_ITEM_LINEgainsxpnl, SPA label/timing/gating + rebuild. (done; indev/done/) - plan-overview-polish — Overview landing punch-ups (→ 1.0.0a15). Overview
tables get a
Static | Interactivetoggle (curated exhibit default, CsvGrid on demand; the one table exception to the all-CsvGrid rule, since it's the demo landing); density/exceedance uPlot capped at 720px; x-axis cropped to ~q(0.001)..q(0.999)(client-side, mirroringAggregate._limits). Design call: no upstreamplot_hero(FCCs share no base; our uPlot is the hero). (done; indev/done/) - plan-grid-full-chrome — useful CsvGrid (→ 1.0.0a16). Bumped csv-grid
3.1.0 → 3.9.0 (pinned commit; 3.1.0 predated copy/save export). Full chrome
on by default (fzf + column filters + status bar + copy/save); Expand/
Contract only from 6 cols up; removed the custom per-tab CSV download buttons
(grid handles export;
/frame/*.csvendpoints stay for full-frame access). (done; indev/done/) - plan-chrome-about-download — hamburger + About + session download
(→ 1.0.0a17). Top-right hamburger (Help / Download / About) replaces the
?; About panel holds the tool versions (moved from the header, + uPlot/Bootstrap defines); newGET /v1/session/models.agg?form=raw|aggdownloads the session's built programs (raw = as typed; agg = canonical/re-loadable). (done; indev/done/) - Example-source switcher (closed — superseded by
plan-relink-library/ 1.0.0a19.aggregatemerged its three shipped libraries into onelibrary.aggat a159, so there is no longer a set of sources to switch between. The axis that replaced it isGET /v1/examples?group=topic|kind|roleover the tag namespaces. The hamburger's greyed-out "Example source…" placeholder should be retired or repointed at the grouping picker.) - Revisit a dedicated severity-stats view (the "sev stats" sub-button
was dropped — no clean upstream accessor). Note
sevbecame a buildable kind in a19, so the object is now reachable from the playground.
The plan behind these is the harness plan of 2026-07-29; one dev/plan-*.md and
one version bump each.
-
plan-relink-library — catch up with
aggregatea148 to a174 (→ 1.0.0a19). Examples read offbuild.recipes/Recipeinstead of the deletedexamples.agg;?group=topic|kind|role+/examples/heroes;bivariate→bvagg;sevbuildable; new/objects/{id}/meta; theactual_*/validation_description/recipesrenames followed. (done; indev/, move todev/done/when the stage set closes) -
plan-all-branding — aggregate Loss Library (aLL) (→ 1.0.0a20). Two-line banner (name over "description to distribution" in grey small caps); name through title / meta / manifest / sw / About / Help / README / package description. No-dashes-as-punctuation rule adopted into
CLAUDE.md, user-visible strings swept. (done; indev/) -
Dash tidy: the ~190 legacy
--glosses in internal docstrings and comments. Deliberately deferred out of a20 so it does not bury the staged diffs; the rule inCLAUDE.mdsays they are cleaned as their file is next edited. Promote to its own tidying commit if the author would rather have it in one go. -
plan-echarts-exhibit — ECharts engine + two-panel Overview (→ 1.0.0a21). uPlot retired;
web/src/charts/with a served house theme (/v1/meta/style) and an exhibit per kind; density + EP panels with an exact index-aligned cursor link anddataZoom; new/objects/{id}/unit_density_df;sevgains a sampleddensity_df; Overview header block off/meta; duplicate Summary dropped from More. Bundle 187 → 353 kB gzip, now split four ways. (done; indev/) -
plan-exhibit-punchups — first inspection acted on (→ 1.0.0a22). Control row (log y / survival / full x / reference lines), sticky per browser;
dataZoomrescales the y-axis; distortion and bivariate drawn square; program disclosure dropped; exhibit titles trimmed. Plus two bugs the inspection surfaced: a per-object read race that made the landing page 500 intermittently for portfolios, andxpnl-over-port / unresolved-reference turned from 500s into 422s. (done; indev/) -
plan-exhibit-punchups-2 — second pass (→ 1.0.0a23). Discrete densities drawn as steps (
steps-mid); capital anchors are faint dashed verticals with top labels instead of points that could never sit on the curve; return periods rounded to integers. Smoke test reworked to replay captured fixtures so it needs no server. (done; indev/) -
Eyeball the Overview. Still outstanding. The smoke test proves the data reaches each chart in a drawable shape and that the panels hold the house aspect at both breakpoints, but not that any of them looks right, and the Chrome extension has not been connected in any session so far. Check all six kinds, both breakpoints, and the five toggles.
-
Watch the full-resolution render cost. (Closed by a37, and by an answer better than either option recorded here.
sampling: 'minmax'reduces each series to the min and max per device pixel before the path is built, so a portfolio hands ECharts a few hundred points rather than six polylines of 65,536, and it re-expands on zoom because the sampler runs after the dataZoom filter. It was adopted to fix the step rendering, not the cost; the cost went with it. No server-side binning, as required.) -
Draw atoms as atoms. Solved in a27 by dropping the binning entirely rather than by detecting atoms, which is not possible from the frame: a tall bucket and a point mass are the same number, so there is no threshold. The plots take every grid point;
resolution='display'survives for the Density table. Gzip made the payload a non-issue (3.65 MB to 0.35 MB on the wire). (done) -
The author is not sold on ECharts (raised a28, alongside the step / anchor / surface asks). Recorded so it is not lost: if the exhibits still do not earn their keep after a28's changes are seen, the question is whether the library is the problem or the chart designs are. Worth separating before any swap, because most of the a26 to a28 fixes were design errors (wrong rectangle measured, wrong default orientation, binned data) rather than anything ECharts did. a29 adds one more to that column: the reservation was aimed at the wrong rectangle for two kinds. Being settled by experiment: the a30 Plotly spike puts both engines on the same data behind a switch.
-
Plotly evaluation spike (→ 1.0.0a30).
aggandport, behind adrawswitch in the exhibit control row. The work turned out to betwoPanelData, the engine-neutral decision step both renderers now read, rather than the Plotly code.plotly.js-gl2d-dist-minand not basic: basic registers bar, pie and scatter only, and its SVGscatterwould choke on the 2**16 points a27 ships. Parity asserted in the smoke test, including that Plotly log ranges are in exponents. (done; moved todev/done/) -
Look at the two engines side by side. This is the whole point of a30 and nobody has done it: the Chrome extension has never connected in any session, so no rendered chart from either library has been inspected. Build an
aggand aport, flipdraw, and decide. If Plotly wins, lifttwoPanelDatainto a real IR withto-echarts/to-plotlyadapters and shrink the bundle with a custom build registering onlyscatterandscattergl. If it loses,engine.jsandplotly-panels.jscome out and the dependency with them; keep thetwoPanelDatasplit either way. Update (a38): the real IR arrived, upstream rather than app side: the library's chart IR (dev/plan-chart-ir.mdthere) with the surface pilot at a38 (/chart/{name}route,chartdoc-to-echarts.js,surfaceGriddeleted). The two-panel family migrates onto it chart by chart as the library conversions land;twoPanelDataremains the app side seam until then.**Closed 2026-08-09.** The engine comparison is moot: the app assumes IR-based charts always, so there is one renderer and no second engine to weigh it against. `twoPanelData` is not lifted into an app-side IR, it is deleted as each emitter lands. See `dev/plan-plot-ir-api.md`. *(Done at a62: it and the whole of `exhibits.js` are gone.)* -
greater_tables alongside the current tables (→ 1.0.0a31). One new
GET frame/{which}.htmlroute mirroring the.csvone, rendering server side on the real DataFrame so the row index sparsifies.renderExhibitstays and stays the default; GT is reached by?tables=gt, no user facing switch. Row emphasis preserved as a<tr>class. (done; moved todev/done/) -
Compare the two static table renderers (→ 1.0.0a32). Settled by the author: "the GT tables are a delight". The comparison ended by replacing both sides, since
greatest_tables(GT2) arrived with a semantic document IR and a client-side walker, which is a better answer than either. The hand-builtrenderExhibitand the 5.x html path are both gone. -
Upstream
greater_tablesnit (closed by the same move). GT2 has no import side effects at all, by design, so thePandas4Warningand the warnings-filter pollution are gone with the 5.x dependency. -
Table view everywhere, one switch (→ 1.0.0a33). The header menu's Tables section steers the whole page; the Overview keeps a second affordance for the same value. Price frames travel with their documents, since a POST computes them. Gated on row count, so density stays interactive.
-
Look at the static tables. The walker has been verified end to end against real documents in Node (sparsified stubs, flags, negative cells, raw values in the CSV export), but nobody has seen one in the page. Build a portfolio, since the two level row index is the whole argument and an Aggregate does not show it. Then walk the tabs: More, Reins and Price all render statically now and none of those have been looked at either.
-
Math in tables and titles. The walker emits
\(...\)for page MathJax unless akatexobject is passed, and the SPA loads neither, so a$...$cell would render as literal delimiters. Nothing sends one today. It is the same decision as the chart labels, so make it once for both; it is now pressing on the chart side, because documents arrive carryingChartDoc.tex(library a209) and the adapter drops it. Held with the chart half atdev/plan-plot-ir-api.md, item 8, where the ruling is that the IR emits a TeX and a plain-text form of every label and the renderer picks one. -
Report to the greater-tables side: its
requires-python = ">=3.13"forced this repo's floor up from 3.11. (Fixed upstream: 6.0.0a2 puts the floor back to 3.11 and says it verified 3.11, 3.12 and 3.13. Acting on it here is part of the catch-up below.) -
Catch up with
greater-tables6.0. The sibling checkout ran from 1.9.0 to 6.0.0a4 while this repo was elsewhere, and a37 followed exactly one thing from it:TableSpec.formatsbecameformatters, which had 13 tests red onmain. Both harnesses (check-frames.py,check-adapter.py) are clean against 6.0.0a4, so nothing is broken; these are opportunities, not breakage. - Putrequires-pythonback to>=3.11. a34 raised this repo's floor to 3.13 solely because GT declared it, and 6.0.0a2 reverses that. The classifiers go back too. - The deploy pin is now actionable. GT is publishing on the 6.0 pre-release line, so the standing note below about pinning6.0.0rc1has something to point at. Check what is actually on PyPI before pinning; pip still ignores pre-releases unless the pin is explicit. - 6.0.0a4 givesratio_colspercent rendering again, and adds house format defaults (float_format,int_format,ratio_format,date_format,table_float_format).tables.pycurrently spells out its own per-column strings inFORMATS; some of that may now be a default worth inheriting rather than restating. - The walker moved with it./v1/assets/gt-render.esm.jsserves whatever the install carries, so 1.10's docs pass and 1.11's "string columns pass through as text" are already live in the browser and have not been looked at. -
The 3-D surface is sugar, not substance (author's verdict after seeing it, a29). "Quite impressive. Fast. But more sugar than substance." It stays, since it is built and its chunk is lazy, so it costs the landing path nothing. Do not invest further there. The verdict sharpens the standing reminder above: the open question is what is worth plotting, not what can be rendered.
-
REMINDER for SM: better things to plot. The author's note, verbatim: "this was a general comment that i need to work out better things to plot. Just remind me if i don't come back to it." Not an api task. Raise it next time the exhibits come up.
-
Reinsurance-aware pricing. Landed in a27 as
POST /v1/objects/{id}/reins_price. The a26 blocker (no public way to calibrate on the gross basis) dissolved once the author pointed atprob_loss_assets: aGridDistributionover thereins_density_dfcolumn supplies the(p, L, a)anchor,Pentagon.solvethe premium target, andAggregate.calibrate_distortionsruns against a small view of that basis. No library internals reproduced. (done) -
Upstream, small: let
calibrate_distortionstake its distribution. Landed upstream better than asked:calibrate_distortions(reins_view=...)at a223, fixed for the shapes this api needs at a250 ([Reins-Density-Fuzz]), and richer than_BasisView's three bases (gross,ceded,net, plus the occurrence intermediates on two stage programs, perAggregate.reins_views).GridDistributionis public. The shim and_REINS_BASESare deletable on a sync to a250 or later, and their deletion is scheduled as phase A3 ofdev/plan-pricing-exhibits.md. (done upstream; app-side deletion pending in that plan) -
Hero gallery empty on a first page load (not reproduced). Reported by the author; populated on the next load. The server side is clean:
/v1/examples/heroesanswers 200 in ~2 s cold and returns all eight, including fired concurrently with/v1/examplesand/v1/metaacross four separate cold processes, and the service worker never touches/v1/*. a27 split the fetch and render error paths (they shared one silent.catch), added one retry after 750 ms, and logs on give-up. Next recurrence: check the browser console for[aLL] hero gallery.
Server policy (2026-07-29). The author starts and stops servers; the tooling here must not.
dev/scripts/capture_fixtures.pyanduv run pytestboth drive the app in-process throughTestClient, binding no port.
-
plan-examples-find — fuzzy find + hero sparklines (→ 1.0.0a24). Pinned search box in the dropdown and a Ctrl+K palette, both uFuzzy over name / kind / tags / note, flat ranked list while searching; hero cards upgrade from a placeholder gradient to a real density silhouette from a cached
heroes/sparklinespayload fetched after first paint. (done; indev/) -
Put the hero gallery in the Examples dropdown. a37 took the cards off the top of the page, where the author did not want them, and left the landing build: one
role:heroentry is still picked at random and built, so the page arrives populated. What is gone is the showcase, and it should come back somewhere findable.pickRandomis still inmain.jsand/v1/examples/heroes/sparklinesis still on the server for it; the SPA wrapper for the sparklines came out and is two lines to restore. -
Replace the lede.
web/index.htmlcarries placeholder copy where the hero row was, sized at two lines. The author's to write. -
Retire or repoint the hamburger's "Example source…" placeholder. (retired at a69. Shipped greyed-out in a17 for a source switcher that a159 made moot: the three shipped libraries are one. The live axis is
?group=topic|kind|role, reachable from the Examples menu, so there was nothing left to repoint it at.) -
plan-more-tab — More as a tab, Bounds, Reins exhibit (→ 1.0.0a25). More is a pill whose pane carries a Reins-style sub-button row (Validation / Stats / Density / bs window / Info); Bounds ships greyed out; Reins gains the gross / ceded / net two-panel exhibit above its tables. Build errors now render on Overview rather than in a sub-menu. (done; in
dev/) -
Reins ceded density is a first-bucket spike on the shared linear window, since the ceded distribution is small next to the gross. The
log yandfull xtoggles cover it for now; if it stays hard to read, give each series its own crop rather than one shared window. -
Bivariate 3D viewer (→ 1.0.0a28).
echarts-glsurface on the joint density behind a dynamic import (own lazy chunk, 165.9 kB gzipped), linear and log height, falling back to the heatmap without WebGL. The downsample to 128x128 is client-side after all: the joint payload is already only 2,560 rows, so a server-side reduction would have saved nothing and added a route. (done) -
Nobody has seen the 3-D surface render.
surfaceOptionis pure and the smoke test checks the mesh is complete and has relief, but WebGL is not exercisable offline. First look should check: does the ridge read onCopulaWindFlood, is the log floor the right depth, and do the wall projections show the marginals usefully or just add clutter. -
The percentile reference lines come off:
dev/done/plan-no-reference-lines.md, canonical here and pointed at from the library'sdev/done/. Executed both sides the day it was written, 2026-08-13: LIB a271 deletedCAPITAL_ANCHORandLEE_ANCHORSand the marks they built, app a98 is one tooltip and two stale comments, since the app draws what it is served. What is left is the mean, and break even on a P&L. Browser pass done on all three kinds. One thing to know: the mean's label changes side, taking the right as the only vertical under therightmostrule, and the rule was left alone. (done) -
The reflected reading, verification only:
dev/done/plan-chart-reflect.md, the app half of the library's plan of the same name, paired rather than symlinked since each repo owns its side. Both halves are written: the app at a96, the library at a269, which is in the library's working tree rather than committed. The upstream question closed the app's way, a269 composing the two probability readings with one flip and noREFLECTED_RETURN_PERIOD_MAP, soreading-map.jsand its tests need no edit.Verification steps 1 to 3 ran clean on the a269 sync, 2026-08-13: `dev/fixtures/charts.json` re-captured and `smoke-charts.mjs` all clear, with `reflect` offered on exactly the six documents that declare a complement axis (`agg`, `severity`, `distortion`, `pnl`, `reins`, `envelope`) and absent from `port` and the joint surface. **What is left is the browser pass**, step 4, whose load-bearing check is that `reflect` with `return period` opens out the *other* end of the curve. If it changes nothing there, a double flip is back somewhere. -
The joint surface, end to end:
dev/done/plan-3d-plot.md, three parties, the canonical copy here and a symlink in the library, both moved todev/done/2026-08-21. This side is complete: a72 the api half (section 3, the three query parameters, the ceiling setting and the chart document cache), a73 the foundation (section 4.1's one decode, section 8.3'snode --testrunner, theecharts-glpin), a74 the drawing geometry, a75 the two halves read against each other, a76 the relief and both author rulings, a77 the look, a78 the controls, a79 the cuts, the marks and the walk, a80 the window box, with later fixes through a92. Section 4.2.1 was ruled 2026-08-12: keep the full grid rule, so the derived quantities stay this side and the library emits the whole reduced grid withwindowas the drawing range inside it. Section 4.2.1.1, the library serving the total lattice and kappa, is declined by the same ruling. What is left is entirely library, two edits carried byaggregate_REFACTOR/dev/plan-3d-plot-LIB.md:edge = "mid"and the whole reduced grid. Nothing here changes when they land, verified 2026-08-21 againstwindowRangeand thesurface-grid.jsdecode. The one chore on landing is re-capturingdev/fixtures/charts.jsonand re-runningsmoke-charts.mjs. Until then every conditional and every mark is computed on the part of the grid that is on screen, up to 4.9 percent out on kappa, and thewindowbox set to 0 is the escape hatch. The prototype stays indev/prototypes/joint-surface/under section 8.0's rule, as the reference the shipped surface is diffed against. -
The Pricing pane through the official channels:
dev/plan-pricing-exhibits.md(canonical here, symlinked in the library), FINAL 2026-08-12. Calibrate, Allocate, Evaluate subtabs served bypricing.calibrate/pricing.allocate/pricing.evaluateexhibits keyed on new result objects; a debounced pentagon preview line;[Calibrate]replacing[Price]. The library's five phases landed ataggregate1.0.0a259 to a263, with execution notes and nine recorded divergences in the library'sdev/plan-pricing-exhibits-LIB.md. Three phases here, all landed: A1 routes a83, A2 pane a84, A3 deletions a85.pricing.pyis thin runners with no pandas, andtables.FORMATSholds the two sharpen entries alone, which the sharpen leaf's own cutover (above) deletes. -
SpaceMouse on the joint surface, and the surface out of the app:
dev/done/plan-spacemouse.md, app repo only, CLOSED 2026-08-12. Four phases: a86 the mesh export, a87 the probe page, a88 the device layer plus the camera integrator, a89 the feel, then a90 the probe findings from the author's unit (the combined 12-byte layout, travel of plus or minus 350, one multi axis collection, no double action from 3DxWare) with the two bugs that run found, a button mask that could fire its own camera reset and a vertical pan running against the hand, and a91 the color ruling, GLB with per vertex viridis read against the colorbar. The relief's row carriesmesh | .glb | .obj | .stl,spacemouseandfeel; Chromium only, feature-detected, greyed elsewhere, iPad path untouched and theecharts-glpin unmoved. Five residual readings (session lifecycle under the puck, sleep and wake, zoom and twist direction, the GLB in 3Dconnexion's viewer and the STL in a slicer, the greyed control in Firefox, Safari and iPad) are recorded in the closed plan's "What stays unread" section, and come back as punchlist entries if they matter. -
The app on an iPhone and an iPad:
dev/done/plan-idevice-ui.md, FINAL 2026-08-14, extended and re-verified 2026-08-21. Five defects, SPA only, no api or library change. All three code phases landed 2026-08-21. a115: the group and leaf strips are laid out at their selected width so they stop moving under a thumb, andtouch-action: manipulationonbodystops a double tap zooming the page. a116: a vertical up / readout / down control in the editor's right margin, the counter reversed to count up JupyterLab style, the cap from 20 to 500 with a 256KB ceiling, the unbuilt draft stashed and handed back, the walk ending on a document change rather than on any keydown,Ctrlbound besideModand the key hints naming whichever modifier the device reports. a117:charts/touch.js, a capture-phase shim giving touch events theoffsetXthatecharts-glreads off the raw event, so a tap on the 3-D surface picks again, and oneresetViewreached from the button, the double click and the puck, with theresetbutton now on every chart and last in its group. -
The iPad round for the above, phase 4, owed. Nothing in a115 to a117 can be verified from a Windows desktop: the pick defect lives in a branch Safari takes and desktop Chrome does not, and the modifier finding rests on a platform test that is false on Windows. Fifteen minutes against the six checks in the closed plan's section 6. Two things it may send back. The tap in check 5 can fail in its second half, a deliberate tap over 300ms being refused by zrender no matter how good the coordinates are; the recognizer for that is sketched in the plan and deliberately unbuilt. And section 6.1 is unconfirmed: whether iOS Safari applies focus zoom to a
contenteditableas it does to a form control, which if it does means every tap into the editor on an iPhone zooms the page, a larger source of the "floating around" report than the double tap and one thattouch-actiondoes nothing about. Its fix is pre-specified, a 16px.cm-contentunder 576px in the editor theme, and takes its own bump. Also open for a ruling, from the a117 notes:resetViewrestores the relief's readings on a surface only, socontourstoggled off on aheatmapsurvives a reset. -
The 2-D control strip goes per panel, and three axes stop lying (→ 1.0.0a121, against
aggregate 1.0.0a314).dev/done/plan-2d-punchups.md, both halves executed 2026-08-21.logsplit intolog xandlog y, the seven readings moved from one centered row into one group per panel keyed on the panel id,full rangestopped falling back to the drawn extent so a probability axis stops being labeled to 1.5, and the return-period window stopped being discarded outright, which was four independent faults on two lines ofxyPanel. Properly fixes the a-generation punch item "log y on rh plot triggers reshape/draw of left plot" (dev/api-punchlist.md:238). Two further rulings taken on execution and recorded as decisions 10 and 11: the log release acts on a density ordinate alone, keyed on the axis unit so it survivesinvert, and a panel offers on every axis that can reach a position rather than on the one occupying it now. NoVIEW_KEYbump. Still owed: the browser pass, sections 5 and 6 of the plan's verification, which is the group alignment at both sides ofWIDE_PXand the sticky state carrying across documents. -
The companion axis auto-fits over data the return-period ladder no longer shows. Raised in review 2026-08-21, not ruled, recorded rather than built. Under a period reading the companion is given no window so echarts fits it, which was right when the period axis showed everything and is loose now that
aggregate 1.0.0a314ends the suggested ladder at 1-in-10,000: the visible part of the curve fills 41% to 100% of the axis across the fixtures and 47% on the author's own program. The fix is to take the companion's extent over the points whose period coordinate falls inside the period window, about three lines inxyPanel. See the "left behind" section ofdev/done/plan-2d-punchups.md. -
A linear return-period axis is labeled from zero.
niceWindowrounds the declared(1, 10000)outward to a tick interval and floors the low end at 0, so the first tick reads1-in-0. New at a121 and harmless: the axis was unconditionally log beforeaggregate 1.0.0a314, so the question could not arise. Not fixed with it because clampingniceWindowto a declared minimum would act on every axis in every document. -
Should the per-panel groups carry their panel title in the wide layout too? a121 labels them only when stacked below
WIDE_PX, on the grounds that panel titles are long ("Probability mass function") and the panel headings are already on screen right above them. Turning them on everywhere is one condition inrenderControls. A styling call, open. -
The Examples dropdown reads the library in file order:
dev/done/plan-examples-dropdown.md, complete across a122 to a124, against the LIB half ataggregate 1.0.0a320(Recipe.seq,Recipe.as_read). A122: the payload is one flat file-ordered list with pills and facets, the app's three ordering tables are deleted, and the editor receives the entry's own text rather than a canonical re-render. A123: the three-line row, the pill filter bar with counts,localStoragepersistence shared with the Ctrl+K palette, and the Ctrl+Shift arrow ring walking the filtered list. A124: out-of-order search, measured on the real payload, so thefzfport the plan held in reserve is not needed. Owed upstream, ruled 2026-08-24:topic:pnlandtopic:distortionduplicate their entry's ownkindon fourteen rows, so the pill row spells the same word twice; the author is removing the two tags fromlibrary.agg, and nothing app side changes when they go. -
Catch the app up to
aggregate1.0.0a333:dev/done/plan-library-skew-a333.md, one bump at a140. Turned up by the[Sync]step of the approximation tab plan, which is why it exists as its own bump: nine backend tests were failing on library skew and none of them belonged to that feature. One real defect, a bivariate's moments coming back empty since library a330 restructuredstats_df, and eight test expectations describing surfaces the library has restated (the two sided return period ladder, the joint surface's centered coordinates and whole placed mass). Nothing owed upstream: two of those tests were readingdetailand the emitted mass against quantities the library never promised, and both now assert what_joint_surfacedocuments. -
The Approximation tab:
dev/done/plan-approximation-tab.md, one bump at a141. The More row's new leaf, between Tail behavior and Window, with a Plot / Summary switch inside the pane rather than two sibling pills: the navigation is two levels andcheck-nav.mjsguards that shape, and the two are readings of one question so they keep one address. Consumes LIB a331 to a333 and needed no server change at all. Eight divergences in the plan's execution notes, the load bearing ones being aheaderhook onloadExhibitLeaf(the switch has to be rebuilt insidedraw, which re-runs on both table flips) and the first chart instancepane-morehas ever held, whichdisposePaneChartandclearPaneshad no branch for. TheRerename rode in the same commit on the author's request. Open, upstream and not blocking: the chart payload is 16.3 MB against theaggchart's 2.3 MB, thirteen series over the full 65,536 point grid, taken to the LIB side as a sizing question. Nothing app side is owed either way, since a smaller emission lands here with no change. -
The Pr Ruin pill:
dev/done/plan-pk-tab.md, one bump at a142, consuming LIB a339 to a341 (the engine lift,eventual_ruinwithRuinResultand theruinexhibit, theruinchart with its downsampling), which landed concurrently from the same plan; the LIB execution notes were read before any app code. Last pill in the Pricing row, after Evaluate: the shared pricing form plus a probability of default box, over the two-panel chart and the exhibit stats strip, live to the form through one debounced POST. Divergences indev/done/plan-pk-tab-API.md, the load bearing ones being nocan_ruinflag (the pill gates on the chart, the Plot mechanics), the new POST route the plan's "nothing new" line underestimated, andsample: trueas the wire spelling of the seed re-roll. Nothing owed upstream. -
The reinsurance structure diagram:
dev/done/plan-structure-chart.md, three bumps, consuming LIB a349 to a351 (the'tower'panel kind andTowerBlockon the chart IR, thestructureemitter, the matplotlib renderer). The library half landed first and deliberately left the SPA drawing nothing at all, since it pinnedCHART_IR_VERSION = 2and refuses anything later. a152 [Tower-Panel] closes that window and draws a tower, with the one row ratio layoutpanelLayouthad no notion of; a153 [Diagram-Leaf] puts it at the head of the Re row and lights that group for a reinsured P&L, which is the first time that group has been live for one; a154 [Structure-Lee] carriesleeandannotateon the chart route, without which the Lee curves could not be asked for at all. Three rulings and nine divergences in the plan's execution log, the load bearing ones being the route parameters (the plan called the app side "the translator plus one nav leaf" and there was no way to reach half of what it described) and the layout, which is in the adapter and not inmount.jswhere the plan looked for it. Nothing owed upstream. Eyeballed at a154 and three defects came back, all of them the library's loss window; they were specified inaggregate'sdev/done/plan-tower-window.md, landed there at a352 and a353, and consumed here at a155 [Tower-Log] along with the app's own half of the log reading: one decade floor per quantity axis rather than per panel, the floor strictly under the smallest value drawn, bands and boundary ticks that cope with zero,log yoffered once per axis and acting on every panel naming it, and a torn top edge on an unlimited block. Eyeballed on log and approved, with one defect: the switch appeared to drive one stage's quantile curve and not the other's, which turned out to be a reading stored against a panel that no longer offers one, from the window where a154 ran against a352 documents. Fixed at a156 [Stale-Companion-Reading], along with labeling the two control groups by their axis, since side by side they were identical and unlabeled.
-
UnderwritingLexer.preprocessraises a bareAssertionErroron an unbalanced[, sobuild()does too. Ask: aValueErrorwith anErrorReport. The catch inroutes/objects.py::split_programgoes once it is. From[Multi-Statement-Programs]. -
format_program's fallback answers with the preprocessed statement rather than the source, so an unreadable program comes back collapsed onto one line.decl_writer._render_statementcatches everything and returns the statement, and its docstring calls that verbatim, but the statement it holds has already been throughUnderwritingLexer.preprocess: every line break and every run of indentation is one space by then, and the bracket step has padded[and]besides. Sopprogramon a program the writer cannot read prints it flattened, and any caller that writes the result back where the program came from destroys the reader's layout. That is what it did to the API's Reformat button, guarded app side at a137 by asking the parser first (routes/decl.py::_every_statement_parses). Ask: keep the source slice and return that, or report which statements fell back so a caller can decline the answer. The API no longer needs it: since 1.15.0 Reformat renders previewed specs and never reaches the text fallback, and the guard is gone. The ask stands forpprogramand other text callers. -
format_programdropsnote{}andtags{}, on every program. Not a fallback case and not confined to any kind: the writer renders no trailer at all, soagg A 5 claims sev lognorm 10 cv 1.2 poisson note{keep me} tags{topic:x}comes back as the four clauses and nothing else. The API writes the answer back over the editor witheditor.setText, so pressing Reformat is how a reader loses the note they wrote. Found at a138 while checking an author report about a bivariate program, which turned out to be alibrary.aggentry after Reformat: correct in every respect except that itsnote{}had gone. Ask: render the trailer, or say the answer is partial so a caller can decline it. This is the a137 finding one layer down, and the a137 guard does not cover it, because a program whose note is dropped parses perfectly well. No workaround app side: writing back what the library serves is the purist ruling, and the app holds no note of its own to put back. -
format_programcannot read a program whose second statement names something the first defines. It renders statement by statement againstaggregate.buildalone, sosev MySev lognorm 50 cv 1.5followed byagg A 100 claims sev.MySev poissoncanonicalizes the first and drops the second to the fallback above, though the program builds. Resolved app side in 1.15.0 ([Session-Parse]): the API previews in the caller's fork, which resolves a program's own earlier statements, and hands the writer specs. The text route keeps the limitation for other callers. -
The portfolio's density ordinate should declare its full extent, as the aggregate's now does.
aggregate 1.0.0a314(L3 ofdev/done/plan-2d-punchups.md) hadcharts._emit_aggregate.outcome_docpublish the tallest drawn mass as themassaxis'full_range, which servesagg,pnl,discreteandreins. The portfolio emitter is a separate one and still declines, though it crops the same way: on theportfixture the ordinate is cropped 3.75 times, suggested top1.60e-4against a drawn peak of6.01e-4, with no extent published. App side a121 covers it by falling back to the drawn extent, so nothing is broken and the two documents reach the same number by two routes; the declaration would retire that fallback and makefull rangeopen the ordinate on aportas it does on anagg. One line, no contract change, which is why it is here rather than in a round note. -
Two
role:heroportfolios carrynote{}after the last unit, where the positional rule binds it to that unit:TwoLineBookandBodoffWindQuake. Visible as a blank tooltip and Overview lead on the landing gallery. -
DefectiveParetohas notopic:tag, onlyrole:paper; it is the sole occupant of the topic view'sotherbucket. -
chart_enveloperesamples without a seed, so its document is not byte deterministic._emit_bounds._envelopedraws the bracketing curves withweight_df.sample(n=n_resamples, replace=True)and norandom_state, so two identical requests produce different bytes and different content hashes. That is at odds with what the chart IR's hash is for: the api servesdoc.hashas an ETag, and revalidation therefore never succeeds whenevern_resamples > 0. The band itself is deterministic, so the api asserts revalidation only atn_resamples=0(tests/test_bounds.py). Ask: take arandom_state/ seed argument, or derive one from the bounds state, so the document is reproducible. Raised 2026-08-09 while moving the envelope onto the IR. -
A
BivariateAggregatehas novalidation_description, so the api has nothing to put in the status strip's verdict slot and printsn/athere (dev/api-punchlist.mdRound 4 item 3). There is a minimal validation and it is already computed: the tail deficit against a 1e-5 gate, surfaced inbs_descriptionandbs_explanation. But it is a mass-conservation check rather than the moment comparison every other kind reports, so it is not a drop-in and the api should not fake one by relabeling it. Ask: either avalidation_descriptionon the bv that grades the deficit in the same terse vocabulary ('not unreasonable'/'pmf deficit 3.2e-04'), or an explicit statement that a bv is validated on mass alone, so consumers can say so in the reader's words rather than guessing. Raised 2026-08-09 while triaging the status line. -
Recipe.declis''forMinimumDistortion:spec_to_declhas no case for a composite distortion whose spec holds constructedDistortionobjects. Worked around with a stored-program fallback. -
Round 5's four asks, all resolved (the note is
aggregate_REFACTOR/dev/note-from-aggregate-api-round-5.md). 1. Landed better than asked: raw values travel in every exhibit (include_raw, LIB a246) with caller-set extent (max_rows, a247), sospec_extra=was never needed. 2. Consideration rounding landed upstream at LIB a251 (_pnl_considerationrounds at the source); the app's_round_pnl_premiumtext rewrite, idempotent since then, deleted at a95. 3.PnL.value_typelanded at LIB a248; the app's local special case is gone. 4. Superseded 2026-08-13 by[Chart-Marks-Mean-Only], executed the same day (dev/done/plan-no-reference-lines.md, LIB a271 and app a98): the percentile reference lines come off entirely, the readout strip answers the same question by hover, and the mean stays, so the redesign this ask requested is moot. -
Five Pricing subtabs, and the natural allocation:
dev/done/plan-pricing-natural-allocation.md(canonical here, symlinked in the library), drafted 2026-08-14. The pane becomesCalibrate Stand-alone Allocate Plot | Evaluate. Stand-alone prices the parts alone, Allocate splits the whole across them, Plot draws the kappa curves behind the split. Three api phases, all landed: B1 the routes (a103), B2 the pane (a104), the sync (a105). The library half is phases N1 to N5 (aggregate1.0.0a281 to a285) plus the phases ofaggregate_REFACTOR/dev/notes-net-natural-allocation.md(a277 to a280). The api went first by the author's instruction and carried aneeds_split_allocationmarker and a temporarily darkpricing:plotrow meanwhile; both are deleted at a105. Every acceptance criterion of the plan is met, checked in the browser on both reference programs. Both copies moved todev/done/2026-08-20, the canonical one here and the library's symlink with it, which is why the two moves waited to happen together. -
Hints, the doc catch-up, and a headless flag:
dev/done/plan-hints-docs-headless.md, drafted and executed 2026-08-17 against the library at 1.0.0a301. Three independent phases, one bump each. a106:--headless/AGGAPI_SERVE_SPA=0, declaring what the conditional static mount already did by accident, plus a test pinning that/docssurvives it. a107: the Hints button andPOST /objects/{id}/hintsoverwith_hints(library a291), which pins the realized grid into the declaration's ownhints{}so asev agg.NAMEreference to it means one fixed thing. a108: the app'sdoc{{{...}}}defenses deleted, the library having retired the clause at a301. Two ideas from the same list did not land: the PnL face toggle was dropped by the author (the two faces are one statement shape, so it is a typed character), and the custom-library work is parked indev/done/note-session-isolation.md. -
One recipe base, many users:
dev/done/plan-session-isolation.md, the v2 rescope ofdev/done/note-session-isolation.md(the measured evidence file, parked 2026-08-17). Two problems, each needing its own fix: session builds share one recipe base, so one user's declaration is what another user'sagg.NAMEmeans; and the object cache keys on program text, which no longer determines the object once a reference is in it. Phase A0 landed at a109, the standalone finding the note turned up:--libraryre-pointed the Examples menu only while all three build paths used theaggregate.buildsingleton, andSettings.knowledge_basehad never been read. Fully executed 2026-08-18: A0 at a109, A1 to A4 at a110 (the session id, the fork registry, the qualified cache key and every build path routed through the caller's own base), A5 to A7 at a111 (the expiry pane with its rebuild button, sharpen on a deepcopy, the pricing-residue rule). The note, and since 2026-08-18 the plan itself, are indev/done/, the library's debrief folded into the plan's section 5 and the symlink in its tree moved todev/done/alongside. What it deliberately did not do is in the plan's section 8: no content addressing, one browser tab per session with no persistence,cache_maxstill 50, and one uvicorn worker is now load bearing. -
A status page, private by construction:
dev/done/plan-site-status-page.md, phases S0 to S4 at a112. An operator's view at/v1/status/pagebehind a JSON contract at/v1/status: versions against process start, live session forks, cache and build behavior, whether the a110 shared-against-session key rule is firing correctly, and process resources. Three access layers, the primary one being a Caddy matcher on the public block, because both front doors proxy to127.0.0.1:8001and no peer-address test can tell a public visitor from a VPN one. The same fact was a live bug: every audit row recordedip = '127.0.0.1', now fixed innet.py. Two things it deliberately does not do: no metrics export and no controls, section 9 of the plan. Follow-ups, neither blocking: - The audit database has no retention policy and the page now shows it growing. Section 8 question 4 of the plan is left open on purpose; the number on the page is what should prompt deciding it. - Capability drift is live: 16 exhibits and 9 charts registered against the oversight charter's recorded 12 and 8, the difference being the four pricing exhibits and thekappachart from LIB a259 to a263. The charter's state snapshot wants reconciling, which is an oversight task rather than an api one. - The page's key-scope panel will report programs the previewer refused and the builder then accepted, verbatim. Any that appear are an upstream ask againstUnderwriter.preview; none have yet. -
The PnL button, a priced book and one press to explode:
dev/done/plan-pnl-button-punchup.md, complete across a113 and a114. A113: theexploderoute turning apnlinto thexpnlthat walks its layers,can_explodebehind the button's second state, and_has_reinsurancelooking through aPnLto its engine, which had been reportinghas_reinsfalse for every reinsured P&L. A114: the three combined ratios, so press one prices every cession as adepositagainst LIB a306's ladder. Two things a later reader should know. The draftedworking_attachfield never existed, because aratequote against the P&L premium is circular and the library removed the split; and a portfolio engine keeps the unladdered path, so it is still sized offloss_ratiowhile an aggregate is sized off the ladder. Follow-up, not blocking: LIB's D2, whethernet_combined_ratioeventually takes aDistortionand resolves the implied technical premium ratio itself. That is the destination the ratio form was chosen for, and it would reach this endpoint as a field.
-
The status line is written before
maxRowsis applied. 3.10.1's_installrunsrefresh()(body and status) and then_applyHeight(), which re-renders the body windowed but not the status, so a grid that windows keeps "showing rows 1–2,048" in its status bar.loadAllRowscallsrenderStatus()once the load promise settles. Ask:_applyHeightrefreshes the status after it re-renders. Raised 2026-10-17, 1.22.0. -
No way to default the export to raw values. CsvGrid 3.9.0 builds the "Formatted values" checkbox with
checked = truehard coded (csv-grid.es.js:824) and_runExportreads it live, so there is no constructor option and no export default to set.mountGridclears both boxes (Copy and Save) by reaching into the widget's DOM after construction, which works only because_buildScaffoldbuilds them in the constructor. Ask: anexportValues: 'raw' | 'formatted'option. The workaround deletes the day it lands. Raised 2026-08-10, a64.