Repository navigation
Description
Destination
TACC uses ui-react at mint.tacc.utexas.edu in place of the Lit UI, and the client
manager signs off that the SOW's acceptance criterion (§8 — a model input's variable,
standard variable and unit configured in one form submission) is met.
That sign-off closes out the SOW. The map ends there.
Notes
Domain. MINT / SUBSIDE model catalog. See ADR-0002
for the React migration and ADR-0001
for the Hasura backend it sits on. Both have a Traps section — read it before debugging
anything that looks like a permissions or cache bug.
This map carries execution, not just decisions. The remaining work is deploy-and-verify,
so tickets do the thing rather than only decide it.
Contract. The SUBSIDE model-catalog UI SOW with UT Austin / TACC. Its period of
performance has expired (confirmed not to be a blocker) and the engagement is settled
financially, so the only remaining obligation is delivery and sign-off.
Contract number, terms, amounts, billing status and client contacts are deliberately not
recorded here — this repo is public. They live in the private metalearn wiki. Keep them
out of this map and its tickets.
Standing preferences for this effort
- Deploy target is TACC's own small k8s cluster, via the MINT Helm chart. Max has
kubectlaccess. ui-reactreplaces Lit atmint.tacc.utexas.edu(decided; T1 de-risks it).- No UAT walkthrough document — TACC gets the URL (decided).
- Skills:
/grillingand/domain-modelingon decision tickets.
State at charting (2026-08-08). Last code commit 2026-07-20; ~3 weeks idle. ui-react is
containerized and published, 21 routes ported, and has run only on Vercel previews and
localhost. OAuth2 has been exercised on previews and works — but previews use a dedicated
OAuth path for preview origins, so the round-trip at mint.tacc.utexas.edu is still unproven.
The app has never been driven against TACC's own Hasura and CKAN.
Decisions so far
-
Confirm SUBSIDE can live without the un-ported Lit screens —
none are needed; the flip is free. Most are already dead or stubbed in Lit, Analysis and
Emulators have no nav link, thread Summary turned out to be ported, and thread Visualize was
never functional in Lit either. Also settled the rollout: no parallel deploy (no users on
Lit at TACC), Vercel is the test surface, and Lit stays deployed-but-unrouted at the upgrade
as the only undo, removed after sign-off. -
Tag helm-charts 9.0.0-beta.3 and bump the submodule pointer off beta.2 —
the chart is reachable again.9.0.0-beta.3tagged upstream on3d3aca8, submodule bumped
in #82, merged todevelopas200a0d7.
Both confirmations held:ui_react.enabled: falseby default, and the legacyui
component is untouched (values.yaml is +52/-0, noui*template in the diff,_helpers.tpl
append-only). Three facts fell out —ui_reactneeds an OAuth2 client distinct from
Lit's (one callback URL per client, so reusing Lit's breaks the undo — sharpened
#73); its image tag is a monorepo SHA
the bump automation will silently skip, so it is hand-set; and it takes its own host
rather than a path prefix, making the flip a host reassignment. -
Verify CKAN from a browser origin against ckan.tacc.utexas.edu — is CORS actually broken? —
fine in production, broken on Vercel. CKAN echoesAccess-Control-Allow-Originonly for
*.tacc.utexas.edu(not the apex),localhostand127.0.0.1; every other CORS header is
sent to everyone, so it looks enabled when it is not.mint.tacc.utexas.eduis allowlisted,
so production needs nothing from TACC and nothing from us — which killed
#74 (the nginx proxy only serves the
origin that already works, and never touches a preview), closed unopened.*.vercel.appgot
no header — since fixed: Max added the two real Vercel origins to CKAN's nginx map as
anchored regexes and dropped the pre-existing*.github.iowildcard, verified live on every
action the app calls plus the preflight. So
#76 runs wholly on the Vercel preview as
originally written,/datasets/*included, on the branch alias
monorepo-git-develop-mosoriobs-projects.vercel.app— per-deployment preview URLs are refused
and cannot be allowlisted, since the hash changes every push. No public-suffix wildcard is left
in the allowlist, which closes the credentialed-access concern the first fix opened. -
Commit .env.example and local-setup notes so ui-react runs for someone who is not Max —
a.envfile cannot configure the dev server. That was the finding, and it made the
ticket's premise wrong.index.htmlalways loadspublic/env-config.js, so theVITE_*
fallbacks never run. The real fault was one line:HASURA_ENDPOINTpointed inside the
cluster, atgraphql.mint.local. It now points to TACC's public Hasura. A clone plus
npm installplusnpm run devnow shows real model catalog data, read-only, with no
cluster access. I verified this live from alocalhost:3000origin. The ticket also added
.env.example,npm run config:localand a README section, and deleted
.env.development. It deletedMODEL_CATALOG_API, which no code used. That left
#75 with a fixed list of 12 keys.
ENSEMBLE_MANAGER_APImust be set, or thread execution stops without an error. The code is
in PR #83, merged todevelopas
45a6d7e. -
Check whether the OAuth2 redirect URI for mint.tacc.utexas.edu is already registered —
already registered; nothing to do at the IdP. The premise was wrong: Lit uses
/oauth2/callbacktoo (${window.location.origin}/oauth2/callback, hardcoded), so both apps
want the identical redirect URI. The IdP is Tapis, tenantportals— not Keycloak — and
clientminthascallback_urlexactlyhttps://mint.tacc.utexas.edu/oauth2/callback.
Verified live, with negative controls, againstGET /v3/oauth2/authorize, which validates
redirect_uribefore login: the match is exact on scheme, host and path (http://is
rejected), and nomint-*react*client exists. Tapis really is one-callback-per-client, but
the Tag helm-charts 9.0.0-beta.3 and bump the submodule pointer off beta.2 #70 inference thatui_reactneeds its own client does not follow — the two apps want
the same URI and never serve the origin at once (Lit is unrouted). Decision: reusemint,
so there is no IdP change at flip or rollback. The chart's own text argues the opposite and
is wrong for this rollout; it only hard-fails on an emptyclient_id, so"mint"renders —
flagged on #75. Two constraints landed on
#77: the host must be exactly
https://mint.tacc.utexas.edu, and Lit must be unrouted, never re-hosted — parked at a
second hostname it cannot log in, making it a rollback to a broken app. Also rules out a
staging host forui-reactbefore the flip. -
Settle the window.MINT_CONFIG values for the TACC deployment —
two values, not twelve. The deployed Lit app publishes TACC's real config at
mint.tacc.utexas.edu/config.js, so no value had to be guessed. Ten of the twelve keys need
no statement: they derive from the component ingresses or inherit shared chart values TACC
already overrides (google.maps.key,welcome_message). Onlyclient_id: "mint"and
data_catalog_api: "https://ckan.tacc.utexas.edu"must be set. Derivation is proven safe
for Hasura and the Ensemble Manager rather than assumed — the Lit template and theui_react
helper share the sameingress.tlsidiom, and Lit's live output showshttps://for both, so
TACC declares TLS and there is no mixed-content trap. CKAN is the exception:ui_reactderives
it fromcomponents.data_catalog, which TACC does not use (it usesexternal_services.ckan.url,
read by the Lit template only), so the key is omitted and the app falls back to a compiled
default that is right by coincidence — hence the override. Verified live from the production
origin: Hasura and the Ensemble Manager both sendAccess-Control-Allow-Origin: *, the
Ensemble Manager's/v1routes exist, and CKAN sets noX-Frame-Options, so the datasets
iframe will render. Two facts landed on
#76 —ui-reactneeds no CKAN API key
(Lit'sDATA_CATALOG_KEYhas no counterpart; all reads are anonymous GETs), and
ENSEMBLE_MANAGER_APIis now set, so thread execution is in scope for the smoke test. Three
chart cleanups landed on #77: the dead
MODEL_CATALOG_APIkey, the wrong "must be a distinct client" text, and teaching
ui-react-config.yamlto readexternal_services.ckan.url. None block the flip. -
Ensemble Manager calls send no Authorization header — localStorage key mismatch —
fixed in PR #87, merged todevelopas
4f7debf.
Both REST calls read the token by string literal from a key nothing writes, and spread the
header conditionally, so every call went out anonymous with no error. The symptom is now known
rather than guessed, from the Ensemble Manager source: against atapisengine, which is
what TACC runs, submit returns 500 ("Unauthorized" escapes as a plainError) and logs
return 401 — both read as server faults, not a missing credential. The probe could not
settle this becausefetchLoglooks the execution up before it reads the header, so an
unknown id 404s either way. Both calls moved intosrc/lib/ensemble-manager.tsso the header
is built once; the tests assert the outgoing header, not the storage key, and were checked
to fail against the old code. The fix exposed a second defect and did not resolve it:
#88 —ui-reactposts to
/executionEngines/localex, and the only such route is/executionEngines/tapis, so run
submission 404s before auth matters. Submission is still broken at TACC; the log call is
fully fixed. -
ui-react submits runs to /executionEngines/localex, a route that does not exist —
two faults, not one. The engine name was wrong for TACC, and the route was wrong for every
engine except Tapis:server.tsmounts/executionsLocal,/executionsand
/executionEnginesas three separate routers, and the last registers/tapisonly. So a
config key alone would not have fixed it. The engine is now the config key
EXECUTION_ENGINE, andexecutionEnginePathmaps each backend to its real route — the same
map Lit makes inmint-runs.ts:731— so the key is honest for all three engines. The
default islocalex, matching both the chart default for the Ensemble Manager and the Lit
fallback, so one unset value describes the same deployment in three places. The results step
needed nothing:MintResultsreads the engine off the execution row, not from config, and its
localex/wingsrewrite is dead becauseMintThreadnever passesmintConfig. Code is in
PR #89, merged todevelopas1d1ada9.
One constraint landed on #77: the chart must
emitEXECUTION_ENGINE: tapisfor TACC, derived the wayui-config.yamlderives Lit's — a
prerequisite for run submission, not a cleanup. Both halves confirmed live on
#76: TACC's Ensemble Manager publishes
exactly the three separate mounts predicted here, and its Lit config sets
REACT_APP_EXECUTION_ENGINE = "tapis". -
Smoke-test ui-react against TACC's real Hasura and CKAN —
the §8 acceptance criterion passes, for a new input. Signed in asmosorio@portals, a new
model input took label + standard variable (soil__porosity) + unit (m3 m-3) in one
submission against TACC's live catalog. The form is genuinely flattened — one control for
standard variable and unit, which offers the units already used with the variable chosen. The
cmdk trap ADR-0002 warns about could not apply: this picker is plain buttons, not cmdk. Verified
anyway by hit test and a real mouse click. Run onlocalhost:3000, not the Vercel preview —
the preview is behind Vercel SSO, andlocalhostis CKAN-allowlisted with a working OAuth
client, so it tests strictly more. Editing an existing input fails, and that is
#91, now blocking
#77: the junction upsert names a column this
repo's own metadata never exposes, so it is not TACC-specific, and it half-applies. A second,
minor fault rides along — a successful save renders stale until a manual reload. Thread
execution was carved out as #92 rather than
fired at the client's cluster unasked./modeling/*renders against real data; note the region
filter defaults to California, where TACC has nothing — it reads as an empty deployment until
you switch to Texas. All test rows were removed; TACC's catalog is back to its prior state. -
Editing an existing model input fails: the junction upsert names a column Hasura does not expose —
fixed and verified live; the write surface is agraphql_enginequestion, not a TACC one.
Client-only, so nothing to apply to TACC's Hasura.SetConfigurationInputOptionalreplaces the
upsert withdelete_by_pk+insert_onein one document — Hasura runs a mutation's root
fields in a single transaction, so the row is never left missing — and it now fires only when
is_optionalchanged, instead of for every row intoUpdate. Proven under a real Tapis token
with a zero-write probe: validation precedes execution, so the old document returns
validation-failed(the exact_PLACEHOLDERerror) and the new one reaches execution. Why
nothing caught it:generated/schema.graphqlis the admin schema, where the column is
updatable — codegen and all 760 offline tests validate against a schema the app never runs as.
Treat any role-sensitive write as unverified until it runs under a real token. Fault 2 fixed too:
the form refetchesGetConfigurationbeforeonSaved, so a save no longer renders stale.
End-to-end onsimpleModelAnnotated— add, edit label, toggle Optional — all clean, and the
catalog was returned to its exact prior state. Code in
PR #93. One thing deliberately not fixed:
the save is still many mutations, not one transaction, so a mid-sequence failure still
half-applies. No step on this path can fail that way now; ticket it if TACC hits it. -
Thread datasets: ui-react searches CKAN free text instead of the mint_standard_variables field —
fixed and verified live: 3 of 40 annotated variables → 40 of 40. Client-only; nothing to
change at TACC.findDatasetsno longer sends aqat all —packagesMatchingVariableskeeps
the packages whose resources carry the variable, as Lit does. The ticket's premise was
re-measured first and held. Three defects the ticket did not name, each real: resource
narrowing was mandatory, not cosmetic — a dataset matches because some of its resources carry
the variable, and one TACC package holds 35 resources, 1 of which does, so binding all of
them handed the model input files it cannot read;datatypewas read off the first resource,
whichMintDatasetsthen filters the list on; androws=1000was a silent cap, now paged.
Two existing fixtures encoded the bug — they carried no annotation and passed only because
the old code matched prose. Code in PR #95,
CI green. Submit one thread run end to end against TACC's Ensemble Manager #92 is unblocked, with one constraint landed on it:ext_bboxdrops any package
with no spatial extent, and 11 of TACC's 33 annotated packages have none — Texas keeps 16 of
33, the California default keeps 0. Lit behaves the same, so it is not a regression, but a
region-scoped thread cannot see a third of the annotated catalog — now
#97. The same root cause survives
on the browse surface as #96, deliberately
not fixed here. -
Missing dataset metadata must not mean an invisible dataset (decided 2026-08-09, no ticket
of its own to close — it scopes #97). The
four constraints on the Datasets step disagreed about what unknown means: the standard
variable drops it (right), the datatype offers a "Show N" link, dates keep it, and the
region dropped it silently — becauseext_bboxfilters on having a location, not on
location. Region was also the only constraint on the server. The rule is now two rules:
unknown extent is shown and badged, as dates already do; known-but-outside is hidden behind the
counted link the datatype filter already has. Chosen over a single show-everything toggle,
which cannot say why a row was hidden, and over silently widening the results — the exact
failure Thread datasets: ui-react searches CKAN free text instead of the mint_standard_variables field #94 had just demonstrated. Cheap only because Thread datasets: ui-react searches CKAN free text instead of the mint_standard_variables field #94 madefindDatasetsread the whole
catalog, so droppingext_bboxcosts no request. One trap found while scoping it:
packageSpatialCoveragereadscoordinates[0]and handles a bare Polygon only, while TACC also
holdsFeatureCollection×5,Feature,PointandMultiPolygon— moving the filter
client-side without a real bbox extractor would drop those 8 without a word. Datasets step: show the datasets the region filter hides, instead of dropping them #97 blocks
#77: TACC must meet a correct Datasets
step, not an empty one. One thing Datasets step: show the datasets the region filter hides, instead of dropping them #97 does not yet say, seen live on Submit one thread run end to end against TACC's Ensemble Manager #92: Thread datasets: ui-react searches CKAN free text instead of the mint_standard_variables field #94 made
findDatasetsread the whole catalog, so the region now narrows the Datasets step not at
all — an Alaska package (Bethel Elevation) was offered under a Texas framing. That is the
opposite failure to the one Datasets step: show the datasets the region filter hides, instead of dropping them #97 was written for, and the same rule has to settle both. -
Dataset search by variable name searches CKAN free text, not mint_standard_variables —
fixed and verified live:groundwater48 → 12,corpus_nlp0 → 17. Client-only; nothing to
change at TACC. The measured premise held exactly. Substring-match the annotation, prose
dropped — chosen over keep-prose-and-badge, which leaves the count wrong and cannot fix
corpus_nlpat all (Solr splits the name on_before it matches), and over a typeahead on
Hasura's 668 standard variables, where only a small fraction are carried by any TACC dataset, so
a user picks a legitimate variable and gets a confident 0. Substring matching only ever offers
what exists, and it agrees with the Datasets step: show the datasets the region filter hides, instead of dropping them #97 rule: filtering by standard variable correctly drops a
dataset that carries no annotation. A second, independent fault rode along and hit both modes:
searchDatasetstook CKAN'srows=100default while TACC holds 215 packages, so the empty term
listed 100 of 215 and said nothing — nowsearchAllPackages, which Thread datasets: ui-react searches CKAN free text instead of the mint_standard_variables field #94 had already taught to
page.buildSearchQuerylost itsvariablesbranch entirely; it only ever built a query Solr
cannot answer, and this was the second surface it broke. One ticket framing was wrong: this was
never a regression. Lit's own/datasets/searchis dead at TACC — it POSTs to
data_catalog_api + "/find_datasets"(ui/src/screens/datasets/actions.ts:377), the legacy MINT
Data Catalog route, never routed throughDataCatalogAdapter, sodata_catalog_type = "CKAN"
does not redirect it; TACC answers 405 for both modes. So "match Lit" was not available as a
constraint. Code in PR #100, full suite green
at 813 tests; the 22 new assertions were checked to fail against the old code, on a path that had
no test file at all. -
Thread wizard shows 18 of 175 model configurations: the model tree query accepts only sdm#Model —
no type belongs out of the model tree; all three queries drop the predicate. Verified live in
the signed-in app: the Models step now reports 175 where it reported 18, and HAND — TACC's
largest family, 44 configurations — goes 0 → 44. The ticket's premise was wrong.type
classifies a model; it does not say whether a row is one. The ETL only migrated
?id a sdm:Modeland stored the most specific subtype, so every row is a model by construction,
and the 8sd#Softwarerows carry the ontology superclass — MODFLOW ×5, ParFlow, an InSAR
workflow, a particle filter. So_neq sd#Software, the ticket's own candidate, would have hidden
real models. An allowlist is worse and this was measured, not argued:model-catalog-api
keeps one and it is already stale, serving 44 of 55 — #102,
ruled out of scope below. All three sub-questions answered the same way:GetModelFamiliestoo
(registration could not offer any subtype family, so no version could be registered under HAND),
andRegionModelstoo (it shares the query, so a different rule would only make them disagree).
Registration still writessdm#Modelfor a new family, which is correct — read and write are
different questions. Code in PR #101, 802
tests green, the 9 new assertions checked to fail against the old code;graphql.tsregenerated
by codegen from the committed admin-schema snapshot rather than hand-edited, which is worth
remembering — codegen runs offline againstgenerated/schema.graphql, no admin secret needed.
Submit one thread run end to end against TACC's Ensemble Manager #92 is unblocked. The fix also exposed the next wall in the same step, now
#103: the Variables step offers 668
indicators where 147 can find a model. -
Thread execution blocks the flip;
ui-reactmust run a thread before TACC gets the URL
(decided 2026-08-09 by Max, no ticket of its own to close — it scopes
#104). The SOW's §8 criterion is already
met (#76), so Thread wizard dead-ends at Parameters: threadExecutionData is never loaded #104 is not required by the
contract's letter. It is required anyway: Lit runs threads at TACC today, and flipping the host
to an app that cannot would hand the client a regression, whatever §8 says. Chosen over shipping
on §8 alone, and over asking the client — asking would invite a "no" to a question we would not
act on. Consequence: Thread wizard dead-ends at Parameters: threadExecutionData is never loaded #104 is now the largest item left on the map, and unlike Editing an existing model input fails: the junction upsert names a column Hasura does not expose #91/Thread datasets: ui-react searches CKAN free text instead of the mint_standard_variables field #94/Dataset search by variable name searches CKAN free text, not mint_standard_variables #96/Thread wizard shows 18 of 175 model configurations: the model tree query accepts only sdm#Model #98
it is a data path to build, not a query to correct. Sequence it before
#97,
#99 and
#103, which are all smaller. -
Thread wizard dead-ends at Parameters: threadExecutionData is never loaded —
the pipeline now loads from Hasura, and the ticket's premise was half the fault.
threadExecutionDatawasuseState(null)that nothing loaded, as written — but
DatasetsSteppersisted nothing either, callingUpdateThreadDatawith emptydata
andmodelIOagainst a mutation that deletes every binding first. So Continue destroyed
bindings, and Thread wizard dead-ends at Parameters: threadExecutionData is never loaded #104's own measurement that the assignment survived a reload is retracted.
That mattered: loading the pipeline alone would have changed nothing, because there was
never a binding to read back.GetThreadExecution+threadExecutionFromGQLare ported
from Lit'sget.graphqlandgraphql_adapter.ts; Datasets and Parameters now write;
executions load and the summary polls while runs are in flight. Three defects found in
the wiring, all where the React port had drifted from Lit: resource ids were a djb2 hash
where Lit writes MD5 of the URL — and since this ticket is what starts writing those rows,
shipping it would have duplicated every file TACC already had;run_progressis a
fraction, drawn as a percentage, so a finished run rendered as a 1% sliver; andtotal_runs
dropped the input-resource factor, where TACC's own summaries keep it. Verified live three
ways — anonymously for the wholethread_modelssubtree and the executions query, under a
real Tapis token forthread.thread_dataanddataslice.dataset(bothuser-only), and a
zero-write probe of the parameters mutation that reachedconstraint-violationrather than
validation-failed. The running app rendersRuns ✓ Completefrom TACC where every step
readPendingbefore. Code in PR #105,
852 tests green.generated/schema.graphqlis the admin schema — the role trap Editing an existing model input fails: the junction upsert names a column Hasura does not expose #91
found for writes applies to reads too: anonymous sees neitherthread_data, nor
thread.events/permissions, nor thedatasettable. Submit one thread run end to end against TACC's Ensemble Manager #92 is unblocked, and carries
the one thing Thread wizard dead-ends at Parameters: threadExecutionData is never loaded #104 could not prove: the two write round-trips through the UI. -
Submit one thread run end to end against TACC's Ensemble Manager —
a run went fromui-reactto TACC's cluster and finished. ModelSUBSIDE Allocation Specification,POST /v1/executionEngines/tapis→ 202, two real Tapis jobs, one of
which ran to completion and wrote a full output set. That is the firstui-reactrun to
produce output at TACC, and it retires the "unproven path" risk this ticket existed for.
Of the four checks, two pass and two fail. Submit returns 2xx, and the Runs step polls
and tracks status live with no 401 — so Ensemble Manager calls send no Authorization header — localStorage key mismatch #85 and ui-react submits runs to /executionEngines/localex, a route that does not exist #88 both hold under a real submission.
The execution row saysexecution_engine: localex
(#109): a hardcoded literal in
ExecutionCreation, harmless today because the server readsprefs.execution_engine
instead, wrong for every consumer of the column. And the Results step never shows any
output (#110) — two independent
causes, which matters because fixing either alone changes nothing:MintResultsguards on
onPublishResults, a propMintThreadnever passes, so Fetch results makes no request at
all; and the route it should call returns 500 wrapping a 403 from Tapis or CKAN. Results step never shows any output: the Fetch results button is not wired, and the publish route returns 500 #110
blocks Flip mint.tacc.utexas.edu to ui-react #77. The wall-per-fix pattern has finally run out of walls in this half — the
wizard now walks Framing → Results without a new blocker appearing, and the two failures
are at the far end, not one step in. Two workarounds confirmed as sound: Models step Continue does nothing once a thread has execution data: delete_thread_model is refused, and the error is swallowed #107 only bites
a thread that already holds bindings, so a fresh thread clears the Models step, and Variables step cannot save any indicator: it writes a standard-variable URI into a column that references the legacy variable table #106 is
steered around by leaving the indicator empty. Both run failures were data, not code —
an.m4afed to a JSON-reading model, then a CKAN resource holding invalid JSON (a raw
newline at byte 25). Both were diagnosed from the Ensemble Manager log endpoint, which
works: read the log before blaming the client. -
Datasets step: show the datasets the region filter hides, instead of dropping them —
two faults, opposite in direction, and the ticket named only one.ext_bboxhid the 11 of
33 annotated packages with no extent, as measured — butMintThreadalso never passed the
region toDatasetsStepat all, so what did arrive was not narrowed either. One rule had to
settle both, and does: unknown extent is shown and badged! no location; known-but-outside is
hidden behind a counted link.findDatasetsnow drops nothing for the region — it labels each
datasetregion_match: inside | outside | unknownand the UI decides. Verified live at TACC:
Texas 29 offered (18 in-region + 11 badged) and 4 behind the link, whereext_bboxserved
16; California — the default framing — 11 badged rows where it showed 0, which retires the
"reads as an empty deployment" note.ext_bboxis not a server-side version of the same
test: ckanext-spatial indexes bare geometries only, so it also drops aFeatureor
FeatureCollection, and TACC has two of those squarely inside Texas — hence 16 → 18, not
16 → 16. The extractor replaced two partial readers, not one: the region map's
calculateBoundingBoxmissedFeature.geometryandFeatureCollection.featurestoo, so
lib/geo/bbox.tsnow serves both surfaces and the region picker gained the coverage for free.
GetThreadselectsregion { geometries }, confirmed readable under anonymous. Code in
PR #113, 883 tests green; the
Feature/FeatureCollection/Point assertions were checked to fail against both old readers.
Two traps left standing, neither blocking: a bounding box is not the region — Alaska crosses
the antimeridian, so its box spans nearly the whole globe and almost nothing reads as outside it
(Lit is the same; it does not bite Texas) — and the browse surfaces still carry the old fault,
now #114. -
Deleting a problem statement, task or thread leaves the row behind and reports success —
the permission was unsatisfiable by construction, so this is the first fix on the map that
needs a schema migration. Theuserrole may delete one of these rows only while it still
carries a CREATE provenance event; the provenance FKs wereON DELETE RESTRICT. Delete the
provenance first and the row loses its own delete permission (0 rows, reported as success);
delete the row first and Postgres refuses it. Both orders were run against a live database
and neither works, which kills the ticket's own first option and rules out any client-only
fix. The ticket named one failed root field; all eleven failed — every child on the tree is
gated through the same provenance, so only the provenance and permission rows were ever really
deleted, which is exactly the state Submit one thread run end to end against TACC's Ensemble Manager #92's orphan was found in. Six FKs becomeON DELETE CASCADEin graphql_engine PR #14 —
metadata unchanged, structural FKs untouched — and the client deletes bottom-up, never
touching provenance, in PR #115 with
assertDeletedto stop a zero-row delete rendering as success. A second defect had to be fixed
with it: the port dropped Lit'sdataslice/thread_datadeletes, harmless while the
mutation was a no-op but a hard FK error once Thread wizard dead-ends at Parameters: threadExecutionData is never loaded #104 started writing those rows. Verified on the
migrated dev cluster under Hasura's own compiled predicates, in a rolled-back transaction; the
Submit one thread run end to end against TACC's Ensemble Manager #92 orphan is cleared. Two things outlive this ticket. Lit's delete mutations are
byte-identical, so delete is broken at TACC today — which is why Deleting a problem statement, task or thread leaves the row behind and reports success #99 no longer blocks
#77 (decided by Max, 2026-08-09, on the
same rule Thread wizard dead-ends at Parameters: threadExecutionData is never loaded #104 set: a defect blocks the flip only if moving off Lit is a regression). And the
chart's Hasura migration job is apost-installhook only, sohelm upgradenever applies
migrations — TACC needs the six-FK change run by hand, after the flip, preferably as a surgical
run_sqlrather thanhasura migrate apply, whose state at TACC is unverified. -
The indicator is a standard variable, and the Variables step does not block the flip
(decided 2026-08-10 by Max, no ticket of its own to close — it scopes
#106 and
#103). Two calls, and the second one moves
the critical path. Storage:thread.response_variable_idwill hold a standard-variable URI.
The four FKs onthread/taskrepoint frompublic.variableto
modelcatalog_standard_variable, in agraphql_enginemigration on the Deleting a problem statement, task or thread leaves the row behind and reports success #99 pattern — FKs change,
metadata does not, because the relationships areforeign_key_constraint_onand follow the
constraint. Chosen over writing the label, which covers 129 of the 147 producible output
variables today and only decays:etl/load.pywritesmodelcatalog_*tables only, so
public.variablehas had no writer since the DYNAMO migration — treat it as frozen and build
no list from it. Data cost at TACC is one row; the unmeasurable risk is ISI's, so the
migration must map by label and null what does not map, never drop rows. Scope: Variables step cannot save any indicator: it writes a standard-variable URI into a column that references the legacy variable table #106 and Variables step offers 668 indicators; only 147 can find a model #103
both stop blocking #77, on the same rule Deleting a problem statement, task or thread leaves the row behind and reports success #99
set — Lit's Variables step is dead at TACC too, so moving off Lit loses nothing.
ui/src/screens/variables/actions.ts:31hardcodesis_indicator: falseon every entry and
renderResponseVariablesfilters on exactly that flag, so Lit's select renders zero options;
live, 1 of 165 threads and 0 of 55 tasks carry a response variable and none carry a
driving variable. ui-react's step is skippable, so it traps a user who picks but does not stop
one who does not. Variables step cannot save any indicator: it writes a standard-variable URI into a column that references the legacy variable table #106 now blocks Variables step offers 668 indicators; only 147 can find a model #103, and Flip mint.tacc.utexas.edu to ui-react #77 is down to two blockers,
#107 and
#110 —twonow one, Results step never shows any output: the Fetch results button is not wired, and the publish route returns 500 #110; Models step Continue does nothing once a thread has execution data: delete_thread_model is refused, and the error is swallowed #107 is
fixed, see below. One consequence to file when the
migration lands: the Ensemble Manager'sPOST /v1/problemStatements/*/subtasksvalidates these
ids againstvariable, so it will reject every URI — pre-existing, and ui-react does not use that
route. Two corrections from building it (#106,
below): metadata does change — the four array relationships onvariableare built on the
same constraints and go inconsistent — and the consequence for the Ensemble Manager is now filed,
as #137. -
Apply the modeling provenance cascade migration to TACC's Hasura —
delete works at TACC, and the migration alone was never enough. The schema change was applied
on 2026-08-10 (six FKs readconfdeltype = c, no drift, one 100-dayidle in transactionsession
had to be terminated first — Set idle_in_transaction_session_timeout on TACC's Postgres #119, runbook docs: runbook for the TACC cascade migration #118). Step 4, the round trip under a real Tapis token,
is now done: a throwaway problem statement created, deleted and gone after a reload, with
delete_threadanddelete_taskataffected_rows 1anddelete_problem_statement_by_pk
returning a row — the value Deleting a problem statement, task or thread leaves the row behind and reports success #99 could never get. The successful delete is itself the proof the
FKs are CASCADE, since under the oldRESTRICTit raises a foreign-key violation; that is the
migration verified from the app, not fromconfdeltype. Confirmed asanonymousafterwards,
not just in the app — an orphan is invisible to its owner and visible toanonymous, which is how
Deleting a problem statement, task or thread leaves the row behind and reports success #99 hid. Run atlocalhost:3000against TACC's production Hasura, not at the host, and the
literal test was not available:mint.tacc.utexas.edustill serves Lit, whose delete removes the
CREATE provenance as root field 6 before the row delete in the same transaction, so it fails for
a reason unrelated to the migration — a false negative. Origin is not part of this round trip (same
endpoint, same database, sameuserrole); what localhost cannot prove is the deployment, which is
Flip mint.tacc.utexas.edu to ui-react #77's job, and a re-confirm-after-flip constraint is landed there. Two things outlive this
ticket. The migration alone does not fix delete — the client fix fix(ui-react): delete a problem statement, task or thread bottom-up (#99) #115 is required, and Lit
stays broken, so a rollback to Lit is a rollback to silent orphaning. And a stale dev server from
another worktree held port 3000, so two runs exercised day-old code that looked right and produced
a confident wrong diagnosis; the request body gave it away, not the UI. Start dev servers with
--strictPort, and read the request body before believing a live verification. That accident was
a clean negative control — the old client against the migrated database reproduced Deleting a problem statement, task or thread leaves the row behind and reports success #99 exactly,
HTTP 200 with noerrorskey — and it left two orphan rows at TACC that no client can delete,
now #120. -
Models step Continue does nothing once a thread has execution data —
fixed and verified live; the step now saves by diff, and Lit's answer was the wrong one to copy.
Both faults held as written: the mutation deleted everythread_modelrow for the thread against
fourON DELETE RESTRICTchildren, andModelsStephad nocatch, so the refusal was silent.
diffThreadModelskeeps a still-selected row and its id, deletes only deselected rows with
their four children, and inserts only what is new — so an unchanged Continue writes nothing at
all. Keeping the id is the whole point: the children hang offthread_model.id, so no
delete-and-reinsert can preserve them. Lit clears the wall by deleting every child row for the
thread on every save, which destroys the Datasets and Parameters work each time — not copied.
Verified on threadx4gbmq00msmbp9ibunder a real Tapis token, reading request bodies: unchanged
Continue sent zero GraphQL requests and advanced the step; adding a model sentremovedIds: []
with all five deletes ataffected_rows 0; removing it sentmodels: []anddelete_thread_model
ataffected_rows 1; and the kept row's id, data binding andtotal_runs 2were untouched. TACC is
back to its exact prior state. Three things outlive it.insert_<table>(objects: [])is
accepted under theuserrole — Thread wizard dead-ends at Parameters: threadExecutionData is never loaded #104 implied it, this measured it. 21 of TACC's 109
thread_modelrows carry nomodelcatalog_configuration_id, and the step deliberately leaves
them alone: deleting one would hit the same RESTRICT wall on exactly the legacy threads that predate
ui-react. And removing a model still discards its runs without warning — Lit does the same for every
model on every save, so it is not a regression; ticket it if TACC hits it. Code in
PR #121, 921 tests green, the 4 new assertions
checked to fail against the old code. Flip mint.tacc.utexas.edu to ui-react #77 is down to one blocker,
#110. -
Variables step cannot save any indicator —
built. The four FKs onthreadandtasknow reference
modelcatalog_standard_variable; existing values map by label, and a label shared by several
standard variables is nulled rather than guessed (62 labels are shared, up to 6 ways). Schema in
graphql_engine#15, client in
#135. Verified on the dev cluster across all
four cases, both directions: a URI now saves and the bare legacy name is now the one refused.
Three corrections ride along. Metadata does change — object relationships follow a
constraint, array relationships do not, so the four onvariablewent inconsistent and had to
be moved by hand; that sharpens the Deleting a problem statement, task or thread leaves the row behind and reports success #99 rule rather than breaking it. The migration would have
killed the whole thread page, not only the Variables step:GetThreadselected
response_variable { id name }and standard variables have noname. And the stored id is now a
URI, which four screens printed raw, so all four prefer the label. One trap for any migration of
this shape: drop the old constraint before rewriting the rows, or the old constraint refuses
the new ids. Two things outlive it —npm run codegenagainst the dev cluster produced a diff
that is exactly this change, adding and removing no type, so the dev cluster is a usable codegen
source; and the dev cluster is now migrated and ahead ofgraphql_enginemain, so a metadata
apply from main would break it. TACC is untouched: that is
#136. -
Chart never sets EXECUTION_ENGINE for ui_react —
fixed, and verified as a browser sees it: both UIs now saytapis. The chart derives
EXECUTION_ENGINEfromcomponents.ensemble_manager.config.execution_engine.type, the same value
ui-config.yamlgives Lit, so the two UIs cannot disagree about the deployment they are in;
components.ui_react.config.execution_engineoverrides it. Chart in
mint#108, version9.0.0-beta.6. No client change
— ui-react submits runs to /executionEngines/localex, a route that does not exist #88 already taughtui-reactto honour the value. Checked the way the ticket demands, not by
helm template:helm upgradeon the dev cluster with its own values, then
curl http://mint.local/env-config.js→"EXECUTION_ENGINE": "tapis", matching
legacy.mint.local/config.js. Six controls on the render, including that a missing Ensemble
Manager config omits the key rather than failing and that an emptyclient_idstill fails.
The "also worth knowing" was real and rode along:DATA_CATALOG_APIderived from
components.data_catalog, which a deployment usingexternal_services.ckandoes not enable, so
the key was omitted and the app fell back to a compiled-in default — correct only by
coincidence, the same class of gap. It now readsexternal_services.ckan.urlas Lit does. That
was one of the three chart cleanups Settle the window.__MINT_CONFIG__ values for the TACC deployment #75 landed on #77;
the other two landed with it, so Flip mint.tacc.utexas.edu to ui-react #77 has no chart cleanups left and its TACC values are down
to one line,client_id: "mint". Two things outlive it.
#123 does not biteui_react— its
deployment carries achecksum/configpod-template annotation, so a config-map-only change does
roll the pod, which is how the new file reached the browser;mint-uiand
mint-ensemble-managercarry none. And the chart had gone three versions without an artifact —
beta.4andbeta.5wereChart.yamlbumps never packaged, so the repo's newest installable
version was still9.0.0-beta.3. Now released:9.0.0-beta.6is packaged, tagged and
published, verified by rendering fromhttps://mintproject.github.io/mint/rather than from the
working tree. Flip mint.tacc.utexas.edu to ui-react #77 needs no checkout deploy — only the monorepo'shelm-chartssubmodule pointer
bumped to the release commit7130169, the way Tag helm-charts 9.0.0-beta.3 and bump the submodule pointer off beta.2 #70 did forbeta.3. -
Results step never shows any output —
a run's outputs now reach the Results step, and there were three causes, not two.
Lonestar6's maintenance ended 2026-08-11, so the retry this ticket waited on ran on 2026-08-29.
POST .../subtasks/jx8ibyilmsmg1pvt/outputsreturned 200 and wrote a real
execution_resultrow — cause 2 is proved by the row, not by the 200. But the step still
read— No results available —:handlePublishResultsrefetchesGetThreadExecution, the
pipeline and its counters, while the table renders theexecutionrows onlyonFetchRuns
loads — so the rows the server had just written waited for a manual Reload. That is the
ticket's own symptom one click later, so it was fixed here, in
PR #152, merged todevelopas
1ba623b, 933 tests green. Verified as a
first click: the registered row was deleted to restore the exact "before" state, and one
click rendered the output. Three things outlive it, none blocking Flip mint.tacc.utexas.edu to ui-react #77 — all server-side or
cosmetic, and the rows live in Hasura so Lit reads the identical ones.
#153: the registered file is
tapisjob.out, the job's console log, becausegetExecutionResultsFromJobprobes a fixed list
of 15 folder names that omits the archive's owndata_exports/, where the real
interview_full_analysis.jsonsits — and with the right candidate absent, Fuse takes its top
hit with no score floor, so something is always picked.
#154:published_runs,
registered_runsandfetched_run_outputsstay 0, so the step readsPendingbeside a
rendered result, and the client's own comment claiming the server writes them is wrong. And the
result link is a CKAN/tapis-file/...proxy that answersYou must be logged inanonymously
and serves the file with a CKAN session — measured both ways, not ticketed. The habit worth
keeping: a 200 from the registration route is not proof it registered — it said "Outputs
registered successfully" while naming the wrong file. Readexecution_result, and open the
resource. -
Apply the indicator standard-variable FK migration to TACC's Hasura #136 blocks the flip, found while resolving Results step never shows any output: the Fetch results button is not wired, and the publish route returns 500 #110 (wired 2026-08-29). On
develop,
/modeling/thread/:iddoes not load at TACC at all:Failed to load thread: field 'label' not found in type: 'variable'. Variables step cannot save any indicator: it writes a standard-variable URI into a column that references the legacy variable table #106 taughtGetThreadto selectdriving_variable { label }and
response_variable { label }; TACC's Hasura still resolves both to the legacyvariabletable,
which hasname. Validation is schema-level, so it fails even for a thread carrying no
indicator. This is the first defect on the map that takes the whole page down rather than
one control, and its shape is new: the Variables step cannot save any indicator: it writes a standard-variable URI into a column that references the legacy variable table #106 client change and thegraphql_enginemigration are
a matched pair, anddevelopnow carries only half of it against TACC. Every client change
paired with a migration is now a flip risk until Apply the indicator standard-variable FK migration to TACC's Hasura #136 lands. Results step never shows any output: the Fetch results button is not wired, and the publish route returns 500 #110 was finished against a local
client with those two selections reverted toname— temporary, nothing ships it. -
How does the MINT Helm chart pass an environment variable to ui_react? —
It does not, and it cannot be made to from a values file. The chart mounts one ConfigMap
intoui_reactwithenvFrom, and builds it from ten hardcoded keys
(charts/mint/templates/ui-react-config.yaml). There is noextraEnvand norangeover a
values map, so an operator cannot add a variable — the chart itself must change. A second
blocker sits at the other end:ui-react/scripts/generate-env-config.mjscopies only named
keys throughpick(), so it drops an unknown variable even when the pod carries it. A new
runtime key therefore costs three repositories:ui-react
(#206), then the chart anddynamo
(#207, filed on this answer and blocking
#77). This is
#150 again, and Chart never sets EXECUTION_ENGINE for ui_react, so a deployed React UI submits runs to the wrong engine #150's own fix is the
template to copy:EXECUTION_ENGINEreads$cfg.execution_engineunder
components.ui_react.config, with a chart-derived default. Note the chart forwards its two
optional keys by two different routes —WELCOME_MESSAGEreads top-level
.Values.welcome_message, shared with the legacy UI. FollowEXECUTION_ENGINE; Remove the legacy ui Helm component from TACC's deployment #81 retires
the legacy UI.One thing this could not settle: the chart version TACC actually runs.
Settled the same day, and the "unreadable" finding was wrong.dynamois cloned locally;
its org isIn-For-Disaster-Analytics, notmintproject, sogh repo view mintproject/dynamo
fails and an agent searching only themintprojectorg calls it unreadable. It is not. TACC
already pins9.0.0-beta.10, the latest published chart, so Carry BRANDING from the MINT chart to the pod at TACC #207 needs a new release
rather than a catch-up bump. Two more facts came with it:ui_reactis present in
values.yamlbutenabled: falsewith noconfig:key, so Carry BRANDING from the MINT chart to the pod at TACC #207 and
#81 will edit the same five lines; and the
checkout sits on an unmerged branch. Two habits worth keeping: a private repo is not
unreadable until you have looked on disk, and a runtime config key is not shipped until you
have readenv-config.jsinside the running pod. -
Do the shipped TACC and UT Austin logos agree with the brand guidelines? —
Yes, and the provenance is stronger than "compliant": both PNGs are byte-identical to the
filestacc.utexas.eduserves today. The whole strip is a copy of TACC's own
branding-headercomponent — their live stylesheet setsheight:50px, background#222,
centred,--branding-logo-height:24px, so every value measured inmint-app.tsis TACC's, not
MINT's invention. No permission is needed: the UT Brand Standards Manual allows wordmark use
per the guidelines in all digital use without approval, and the
Outside Entities process does not apply because
TACC is a UT unit. Two measured near-misses, both cheap and both now on
#206: the minimum-size rule governs
shield height, not image height, so24pxrenders a 21.7px shield against a 25px floor —
use28px; and required clear space is 16.9px against a 15px separator — use17px. Two things
that outlive the ticket: the UT file is the Informal signature, which the manual restricts
to internal use, but TACC ships that same file in its own public header, so the exposure is
TACC's; and there is no UT SVG — the public vectors are EPS and PDF only, while TACC serves
its owntacc-formal.svgdrawn withfill="currentColor". The habit worth keeping: when a
brand question looks like a legal one, check what the brand owner's own site actually serves. -
Carry BRANDING from the MINT chart to the pod at TACC —
carried, proved in a running pod, and the flip is not the one line Chart never sets EXECUTION_ENGINE for ui_react, so a deployed React UI submits runs to the wrong engine #150 said it was. Both
halves were already built and merged: the chart forwardsBRANDINGfrom
components.ui_react.config.branding(mint#114, mint#115), published as9.0.0-beta.11,
anddynamosetsbranding: taccand moves its pin offbeta.10(dynamo#15,85149e7).
What this ticket added is the proof. The dev cluster runsMINT-9.0.0-beta.11with that same
values key, and the pod's own
/usr/share/nginx/html/env-config.jsreads"BRANDING": "tacc"— which clears the second
blocker #204 named, thepick()filter in
generate-env-config.mjsthat drops an unknown key even when the pod carries it. Both logos are
in the image. The acceptance check could not run at TACC, and that is structural rather than a
gap: it needs aui_reactpod,enabled: falsethere, and turning it on is
#77 — so Carry BRANDING from the MINT chart to the pod at TACC #207 blocked Flip mint.tacc.utexas.edu to ui-react #77 while its own
acceptance needed Flip mint.tacc.utexas.edu to ui-react #77. The circle is broken by closing on the render and landing the in-pod read
on Flip mint.tacc.utexas.edu to ui-react #77. The render is what made this worth doing. Withenabled: truealone, TACC's values
giveAUTH_CLIENT_ID: "mint-local"— the chart default, not TACC'smint— and putui_react
on the chart-default hostmint.localwith no TLS, while Lit keeps
mint.tacc.utexas.eduand theminttaccsecret. So Flip mint.tacc.utexas.edu to ui-react #77's values block is four lines plus
moving Lit's ingress aside, not one. Chart never sets EXECUTION_ENGINE for ui_react, so a deployed React UI submits runs to the wrong engine #150's "down to one line" is now measured and wrong.
Flip mint.tacc.utexas.edu to ui-react #77 is down to one blocker, #136.
The habit worth keeping:helm templatethe client's own values file, not the chart's
defaults — the gap was in what TACC does not set, not in what the chart emits.
Confirmed at TACC the same day, and it staged the flip. Max ranhelm upgradeon the login
node (revision 185); it deployed noui_reactpod, asenabled: falsepredicts, so Carry BRANDING from the MINT chart to the pod at TACC #207's own
acceptance was unrunnable exactly as argued. What the run did settle is the deploy checkout:
~/tacc-values/sharedsits on85149e7, level withdynamoorigin/main, with
MINT-9.0.0-beta.11.tgzvendored andbranding: taccset. So Flip mint.tacc.utexas.edu to ui-react #77 needs nogit pulland no
helm dependency update— only the four-line values edit. One reading trap:helm listprints
the umbrella chartmint-isi-0.3.0and never the MINT dependency version; readChart.lock. -
Apply the indicator standard-variable FK migration to TACC's Hasura —
applied 2026-09-12; all four checkpoints pass. The four constraints point at
modelcatalog_standard_variable,metadata is consistent, threadnzGQkhtRsudfSEHkDGct
carriesTOTAL_WATER_STORAGE, and the Variables step saves an indicator signed in at
mint.tacc.utexas.edu. This closes Flip mint.tacc.utexas.edu to ui-react #77's last blocker.
It cost far more than the runbook. Migration1771200021000_standard_variable_embeddings
runsCREATE EXTENSION vector, and TACC ran PostgreSQL 10 onpostgis/postgis:10-3.2-alpine,
which carries no pgvector, so everyhasura migrate applyfailed. TACC now runs
ghcr.io/mintproject/postgres-pgvector:sha-9d58ec7— PostgreSQL 16.9, PostGIS 3.5, pgvector
0.8.6 — restored from a dump, with all 31 migrations applied and 668 standard variables.
Chart Should helm upgrade apply Hasura migrations and metadata? #117 carries the image and a new
semantic_searchcomponent;mint-semantic-searchnow runs at TACC for the first time.
Three facts change Flip mint.tacc.utexas.edu to ui-react #77. The deploy checkout has moved:~/tacc-values/sharednow carries
chart9.0.0-beta.13, and this window needed both agit pulland ahelm dependency update
— so the note above, that Flip mint.tacc.utexas.edu to ui-react #77 needs neither, is stale.kubectl scaleis refused at TACC
(patchondeployments.appsbut not ondeployments/scale, and the bound rolemint-role
does not exist), so usekubectl patch deploy <name> -p '{"spec":{"replicas":N}}'. And
helm upgraderesets every replica to 1, which restarts services in the middle of a window.
Two rollback copies stay on disk until a few days of normal use pass:
~/tacc-values/tacc-hasura-pg10.dump(md50238080b3e7ed462eabaf1f9e4eee163) and
/mnt/hasura_db.pg10inside the PVCdata-mint-hasura-db-0, 156 MB — the old data directory
was renamed, not deleted. -
Flip mint.tacc.utexas.edu to ui-react —
flipped 2026-09-12, and both things only the real origin could prove now hold. Values in
dynamo#18:ui_reacton with
client_id: "mint", themint.tacc.utexas.eduingress and theminttaccTLS secret, and the
legacyuiingress disabled in the same edit. The legacyDeploymentandServicestay, so
Check whether the OAuth2 redirect URI for mint.tacc.utexas.edu is already registered #73's rollback is in place. The OAuth2 round trip is read from the network log, not the
screen:authorize?client_id=mint&redirect_uri=https%3A%2F%2Fmint.tacc.utexas.edu%2Foauth2%2Fcallback
returns 302, and Tapis validatesredirect_uribefore it draws the login form, so the 302
is the match on scheme, host and path; the callback returns 200 from nginx's SPA fallback,
the app takes the token, and the header readsmosorio. The delete round trip passes as
anonymous— the role Deleting a problem statement, task or thread leaves the row behind and reports success #99 hid from: 39 rows, 40 after the create, 39 after the delete,
with the childtaskrow gone too, so Apply the modeling provenance cascade migration to TACC's Hasura #116's CASCADE is verified from the app at the real
origin. The branding chrome renders with both logos served from this host, and the counts are
TACC's own (55 / 213 / 5,998 / 668). Three things outlive it. The servedenv-config.js
is a better check than Carry BRANDING from the MINT chart to the pod at TACC #207'skubectl exec, because it is the file the browser gets — read it
at the host. A stale token in a browser profile reads as a forced-login regression: the
first load went straight to Tapis, and an isolated context proved the app does not bounce
anonymous visitors, who still get the full Explore surface. And the region filter opens on the wrong
region — signed in, the problem statement list showed one item, and that is the first screen
#80 hands the client, so the handover must
say "switch to Texas".It defaults to California, where TACC has nothing.Re-measured on
Hand the client the URL and get sign-off #80 (2026-09-13) and both halves are wrong.ListTopRegionsorders by name, so the list opens
on Alaska; and TACC holds 40 problem statements — Texas 26, Alaska 6, Ethiopia 4,
California 3, Djibouti 1 — counted asanonymous. So the one-item list seen here was the
signed-inuserrole's view, not the region's contents. The handover line is unchanged; only
its reason is. One thing to file: Lit'sconfig.jspublished
REACT_APP_DATA_CATALOG_KEY, a CKAN JWT, to every visitor; the flip stops publishing it, so
rotate the key when #81 retires Lit.
The route is now clear to the destination — Hand the client the URL and get sign-off #80 is the only step left before sign-off. -
Variables step offers 668 indicators; only 147 can find a model —
built; each picker now offers only what it can act on, and two premises were wrong. The
Indicator picker offers the 147 standard variables a listed configuration produces and the
Adjustable picker 161, each with a link that widens to the whole catalog. Counts per option
were rejected:anonymoushas no aggregates on these tables, so a count costs the same query and
still leaves the dead end pickable — the rule Dataset search by variable name searches CKAN free text, not mint_standard_variables #96 already set. The/modelsfacet is the wrong
list and this was measured, not argued:GetOutputVariableOptionsoffers 148, the extra one
produced only bypihm_flooding, one of TACC's 89 configurations that hang off no software
version, so the tree never lists it. The new queries repeatGetModelTreeWithRegions's own leaf
rule, so the picker and the filter cannot drift. The Adjustable variable filters nothing today
—driving_variable_idis stored and printed only, and no wizard step reads it — so its list
comes from the knowledge base's definition of a driver, "input variables or adjustable
parameters": 154 inputs ∪ 28 adjusted throughmodelcatalog_parameter_adjusts_variable= 161.
Neither half alone is right. Question 3's premise was wrong: threadnzGQkhtRsudfSEHkDGct
holdstotal_water_storage, which is in the 147 and reaches 1 configuration. A different thread
dead-ends —testholds100hr_dead_moisture, which nothing produces — so a stored dead end is
real and the picker cannot prevent it; the Models step now names the indicator and offers a way
back, and the picker pins a stored value the scope does not carry. Cost fell rather than rose,
by reusing neither existing query:distinct_onreturns one row per presentation, so gzipped
against TACC the indicator list is 22.2 KB and the driver list 20.8 KB, against 35.8 KB
for the 668 — and the full catalog now loads only when a user widens. Two faults rode along: the
filter banner printed the raw standard-variable URI (same class as the four screens Variables step cannot save any indicator: it writes a standard-variable URI into a column that references the legacy variable table #106 fixed),
and semantic ranking had to be filtered by the scope or it put the dead ends back. Commit
2206ce0, 995 tests green across 111 files, 12 new assertions each checked to fail against the
old code. The repo'sjunction-key-fieldsguard caught a real cache fault in the first draft —
both queries selected half a composite key, which Apollo cannot normalize. Andnpm run codegen
ran offline against the committedgenerated/schema.graphqlwith no admin secret, producing a
133-line diff that adds nothing but the two operations — the Thread wizard shows 18 of 175 model configurations: the model tree query accepts only sdm#Model #98 note holds.
Not yet specified
-
What breaks under TACC's real data and real auth. Much of this has left the fog.
#76 drove the signed-in app against TACC's
real catalog and found one blocker, #91,
plus one cosmetic fault. The reachability half is gone
(#75); the registration half is gone
(#73); the thread-execution half is
not closing as expected.4f7debfand1d1ada9fixed auth and routing, but the attempt at
#92 never reached the submit button: the
Datasets step could not be satisfied, so Runs stayed locked. That exposed
#94 — now fixed, 40 of 40 annotated
variables. Submit one thread run end to end against TACC's Ensemble Manager #92 was retried on that fix and stopped one step earlier, at the Models step —
#98, now fixed: 18 of 175 configurations
→ 175, and HAND 0 → 44. Submit one thread run end to end against TACC's Ensemble Manager #92 is unblocked. The pattern is worth naming: each fix on this half
reveals the next wall one step further in, and each wall was invisible until something upstream of
it worked. Thread wizard shows 18 of 175 model configurations: the model tree query accepts only sdm#Model #98 was not the last one — resolving it exposed the next wall in the same step,
now #103: the Models step also filters by
the thread's indicator, and the Variables step picker offers 668 standard variables where
only 147 are produced by any configuration — so 78% of legitimate choices dead-end with a
bareNo models found.That is the exact failure mode Dataset search by variable name searches CKAN free text, not mint_standard_variables #96 rejected by name for dataset search, so
the map has already decided against it once. The right list is not missing:useFacetOptions
builds it for the/modelsbrowse facet and gets exactly the 147.Variables step offers 668 indicators; only 147 can find a model #103 blocks Flip mint.tacc.utexas.edu to ui-react #77.Now fixed, and it no longer blocks Flip mint.tacc.utexas.edu to ui-react #77 — see
Decisions so far: the picker offers the 147, the/modelsfacet turned out to be the wrong list,
and the cost fell. Re-measured while fixing it: 36 of the 175 leaves produce no output standard
variable at all, so no indicator reaches them.
Submit one thread run end to end against TACC's Ensemble Manager #92 also carries a constraint from Thread datasets: ui-react searches CKAN free text instead of the mint_standard_variables field #94:ext_bboxhides the third of TACC's
annotated catalog that has no spatial extent, so pick the region deliberately.
The write surface is now measured on the edit path too —
#91 fixed the one blocker it held and the
cosmetic fault with it. What is left in fog is narrow: whether the deployment presents the
right origin at the real host (that is
#77's job), and what the rest of the
userrole's write permissions do against what the client sends — outputs, parameters,
authors and regions have never been driven under a token. The delete path is now measured and
it is broken — #99: deleting a problem
statement, a task or a thread removes the row's provenance before the row, and theuser
delete permission depends on that provenance, so the delete matches 0 rows, returns no error,
and orphans the row — invisible to its owner, still visible toanonymous. Same class as Editing an existing model input fails: the junction upsert names a column Hasura does not expose #91: a
write that is valid against the admin schema and fails under theuserrole.It blocks Flip mint.tacc.utexas.edu to ui-react #77.
Now fixed, and it no longer blocks Flip mint.tacc.utexas.edu to ui-react #77 — see Decisions so far: the permission was
unsatisfiable by construction, so the fix is a schema migration, and Lit is identically
broken, so the flip loses nothing. On
the rate to expect — the authenticated path has now produced six defects (Ensemble Manager calls send no Authorization header — localStorage key mismatch #85, ui-react submits runs to /executionEngines/localex, a route that does not exist #88, Editing an existing model input fails: the junction upsert names a column Hasura does not expose #91, Thread datasets: ui-react searches CKAN free text instead of the mint_standard_variables field #94,
Thread wizard shows 18 of 175 model configurations: the model tree query accepts only sdm#Model #98, Deleting a problem statement, task or thread leaves the row behind and reports success #99) where the anonymous pass produced none, and each one was found only by walking one
step further. Budget for another round after the flip. Seven now, and the seventh is a
different animal — #104. The third
attempt at #92 cleared the Datasets step
for the first time (1 / 1 inputs, and the binding persists across a reload), then dead-ended
one step further in, at Parameters. This wall is not a wrong query.threadExecutionDatain
MintThread.tsxstartsnull, no query ever loads it, and both setters bail out onnull
— so Parameters, Runs and Results are fed an empty object and are, in effect, stubs. Parameters
showsPlease select model(s) first.with no Continue button; Runs and Results never unlock;
anddatasetsCompletereads the same dead field, which is why a satisfied Datasets step still
readsPending. So the earlier wall-per-fix pattern stops describing this: Ensemble Manager calls send no Authorization header — localStorage key mismatch #85 and ui-react submits runs to /executionEngines/localex, a route that does not exist #88
fixed the submit call, but the wizard has never been able to reach it, and no further
one-query fix gets there. Thread wizard dead-ends at Parameters: threadExecutionData is never loaded #104 blocks Submit one thread run end to end against TACC's Ensemble Manager #92 and Flip mint.tacc.utexas.edu to ui-react #77. Two corrections ride along.
docs/adr/0002-...:104lists parameters/runs/results as ported and merged — it is wrong for
all three, so stop trusting that line as a porting inventory. And the flip question changes
shape: this is no longer "does a defect block sign-off" but "does TACC lose working thread
execution by moving off Lit" — a scope call for the client, not a bug to fix on the way.
What Submit one thread run end to end against TACC's Ensemble Manager #92 did confirm is real: Thread wizard shows 18 of 175 model configurations: the model tree query accepts only sdm#Model #98 holds (175 configurations), Thread datasets: ui-react searches CKAN free text instead of the mint_standard_variables field #94 holds (both annotated DEM
packages offered), and the whole Framing → Datasets route is clean at TACC.
Thread wizard dead-ends at Parameters: threadExecutionData is never loaded #104 is now built and the wall-per-fix pattern finally broke — but not for the reason
expected. It was two stubs, not one: the read path and the Datasets write path, and the
earlier reading that the binding persisted was wrong. What is left in this patch of fog is
narrower than it has been: the two write round-trips through the UI, which Submit one thread run end to end against TACC's Ensemble Manager #92 now owns.
The rate to expect has not changed — the authenticated path has produced seven defects, and
Thread wizard dead-ends at Parameters: threadExecutionData is never loaded #104 alone added three more found only by driving the documents at TACC rather than reading
them. Budget for another round after the flip. One thing Thread wizard dead-ends at Parameters: threadExecutionData is never loaded #104 settled that outlives it:
generated/schema.graphqlis the admin schema, and theanonymousrole at TACC cannot
seethread_data,thread.events,thread.permissionsor thedatasettable — so
"it typechecks" and "codegen is happy" say nothing about the role the app runs as. Probe
live, per role, before believing a document.
This patch is now walked to its end. #92
ran a real job on TACC's cluster and read its log, so the two write round-trips it owned are
proven and the submit path is no longer an unknown. What is left here is one wall, at the
far end: #110, the Results step,
which blocks Flip mint.tacc.utexas.edu to ui-react #77. The defect rate held — the authenticated path has now produced ten
(Ensemble Manager calls send no Authorization header — localStorage key mismatch #85, ui-react submits runs to /executionEngines/localex, a route that does not exist #88, Editing an existing model input fails: the junction upsert names a column Hasura does not expose #91, Thread datasets: ui-react searches CKAN free text instead of the mint_standard_variables field #94, Thread wizard shows 18 of 175 model configurations: the model tree query accepts only sdm#Model #98, Deleting a problem statement, task or thread leaves the row behind and reports success #99, Thread wizard dead-ends at Parameters: threadExecutionData is never loaded #104, Variables step cannot save any indicator: it writes a standard-variable URI into a column that references the legacy variable table #106, Models step Continue does nothing once a thread has execution data: delete_thread_model is refused, and the error is swallowed #107, Results step never shows any output: the Fetch results button is not wired, and the publish route returns 500 #110), and every one came from walking one
step further rather than reading code. But the shape changed: this pass found no new wall
in the middle of the wizard, only at its exit. Budget for another round after the flip, and
expect it to be about what the app does with results, not about whether it can reach them.
One habit worth keeping from this pass: both run failures were bad data, and the Ensemble
Manager log endpoint named the cause exactly (Invalid control character ... char 25).
Read the log before suspecting the client.
That last wall is now down, and the expectation above was right.
#110 is closed: a run's outputs reach the
Results step, and what is left over is exactly what the app does with results rather than
whether it can reach them — #153 (the wrong
file is registered) and #154 (the counters
never move). Neither blocks Flip mint.tacc.utexas.edu to ui-react #77; both are server-side, and the rows live in Hasura, so Lit reads
the identical ones. The wizard now walks Framing → Results end to end at TACC. The defect
rate held at one more (Results step never shows any output: the Fetch results button is not wired, and the publish route returns 500 #110 itself made eleven), and Results step never shows any output: the Fetch results button is not wired, and the publish route returns 500 #110 alone added two found only by reading
the row the server wrote and opening the file it named. The next habit this pass buys:
a 200 from a registration route is not proof it registered. -
The model-tree read surface has the same fault in two more places.Settled on
#98: all three queries fixed together, and
agrepoverui-reactconfirms they were the only ontology-type filters in the app — so the
open half of this patch ("does any other query filter this way") is answered: none do. -
The read surface beyond Hasura is a measured fault, not a suspicion — and the browse half is
still unmeasured. Thread datasets: ui-react searches CKAN free text instead of the mint_standard_variables field #94 was not a Hasura fault; it was the data catalog half, which no ticket
had driven under real annotations. The first look past the thread wizard found the same bug again
on the search surface, now fixed (#96):
groundwater48 → 12,corpus_nlp0 → 17. The pattern held — it is every CKAN read that
assumes an indexed field, not one bad call site.What is still unmeasured isThis patch has now graduated —/datasets/browse
and/regions/:id/datasets.
#114, filed while resolving
#97 and measured, not suspected: for Texas
/regions/:id/datasetslists 50 of the 88ext_bboxreturns, out of 215 packages, and the
104 with no extent can never appear. Both faults Dataset search by variable name searches CKAN free text, not mint_standard_variables #96 named are live there — theext_bbox
drop and the silent row cap (RegionDatasets.tsx:23,rows: 50with a box,rows: 20without)
— and both now have a fix to copy rather than to invent: Datasets step: show the datasets the region filter hides, instead of dropping them #97's rule andlib/geo/bbox.ts, and
Thread datasets: ui-react searches CKAN free text instead of the mint_standard_variables field #94'ssearchAllPackages. Region datasets page lists 50 of 88, and hides every dataset with no extent #114 does not block Flip mint.tacc.utexas.edu to ui-react #77, on the judgement that a browse page is
not the first thing TACC meets in a thread; re-decide it if they open the regions pages first.
/datasets/browserides along on Region datasets page lists 50 of 88, and hides every dataset with no extent #114 and is still unmeasured. Keep the habit: check what a
surface truncates before checking what it filters. -
Whether TACC's Hasura carries the same permission gaps as ISI's. Partly measured while
resolving #71 — the endpoint is
https://graphql.mint.tacc.utexas.edu/v1/graphql, it sendsAccess-Control-Allow-Origin: *
(so Hasura is reachable from any origin, Vercel included — the CKAN allowlist is not
mirrored here), andanonymouscan readmodelcatalog_standard_variableand
modelcatalog_unit, unlike ISI. But*_aggregateis absent foranonymous, same as ISI,
so there are still no server-side facet counts. The read half is now settled — the
anonymous smoke test on #76 drove
/models,/variablesand theOutput variablefacet against TACC with no login and found no
gap. ADR-0001's warning aboutanonymousandmodelcatalog_standard_variabledoes not apply
to TACC. The write surface is now partly measured too, and the answer was not a TACC gap:
#76 wrote a dataset specification, a
variable presentation and a junction row under a Tapis token, and deleted all three. The one
write that failed, #91, failed from this
repo's metadata, not TACC's — so stop framing the write surface as a TACC unknown and read it
as agraphql_enginequestion. Now fixed, client-side, with no metadata change, and the
edit path verified live end to end. What stays unaudited is the rest of theuserrole's write
permissions against what the client sends. One slice of that has graduated: the indicator write
is built and proved on the dev cluster, but only under the admin role, so
#136 carries it to TACC and to theuser
role. -
~~Whether TACC's catalog holds the ~303 standard variables and ~107 units the typeahead
assumes.~~ Settled on #76: TACC holds
668 standard variables and 129 units, counted by paging sinceanonymoushas no
*_aggregate. Both are well above the assumption. -
Defect turnaround once TACC starts testing — unknown volume, unknown appetite.
-
Whether anyone but Max can run the authenticated app outside production.Fixed. Tapis
clientmint-localhost-3000now serveshttp://localhost:3000/oauth2/callbackand is the
repo's defaultAUTH_CLIENT_ID;mint-localkeepshttp://mint.local/oauth2/callbackfor the
dev cluster. Clients are named after the origin they serve, since Tapis allows one callback per
client. A real login onlocalhostsucceeded — and immediately exposed
#85, a silent auth defect no amount of
anonymous testing could have found — which in turn exposed
#88. One real login has now produced two
defects; treat that as the rate to expect from the authenticated walkthrough. -
The chart-rendered config has never been exercised, and it is not the config every
walkthrough has used. The dev cluster was flipped as a rehearsal on 2026-08-29:
helm upgradeto9.0.0-beta.5,mint.localreassigned toui_react(image04c5b679,
clientmint-local) and Lit moved aside tolegacy.mint.local, still deployed as the undo.
Both hosts serve the right app. That rehearsal immediately produced
#150, which blocks Flip mint.tacc.utexas.edu to ui-react #77: the chart
emitsREACT_APP_EXECUTION_ENGINEfor Lit and emits nothing forui_react, which then
defaults tolocalexwhile the deployment runstapis. There is no values key to override
it, so no deployment can currently be correct. This is ui-react submits runs to /executionEngines/localex, a route that does not exist #88 returning through configuration
instead of code. The reason no earlier ticket saw it is worth keeping: every authenticated
walkthrough so far, Submit one thread run end to end against TACC's Ensemble Manager #92 included, ran from localhost or Vercel against a hand-written
env-config.js— the chart's own config map has never been under a browser. Expect more of
this class at the flip, and prefer a rehearsal on the dev cluster over reading the templates.
One known limit of that rehearsal: CKAN allowlists*.tacc.utexas.edu,localhostand
127.0.0.1only (Verify CKAN from a browser origin against ckan.tacc.utexas.edu — is CORS actually broken? #71), so dataset surfaces are CORS-blocked frommint.localand cannot be
judged there.Flip mint.tacc.utexas.edu to ui-react #77 is back to two blockers, Results step never shows any output: the Fetch results button is not wired, and the publish route returns 500 #110 and Chart never sets EXECUTION_ENGINE for ui_react, so a deployed React UI submits runs to the wrong engine #150.Chart never sets EXECUTION_ENGINE for ui_react, so a deployed React UI submits runs to the wrong engine #150 is fixed and the rehearsal
paid for itself twice — the same PR closed a second omitted key,DATA_CATALOG_API, which no
reading of the template had caught either. The class is now named precisely: the failure is a key
the chart omits, where the image's own default then decides, silently and sometimes correctly.
Two of the twelve keys were in that state and both are now derived.Flip mint.tacc.utexas.edu to ui-react #77 is down to one blocker,— but the chart-rendered config is
#110
still only proven onmint.local, so keep the habit: read the servedenv-config.jsat the real
host before believing the flip.
Results step never shows any output: the Fetch results button is not wired, and the publish route returns 500 #110 is closed, and Flip mint.tacc.utexas.edu to ui-react #77's one blocker is now
#136 — which was not a flip risk until
Results step never shows any output: the Fetch results button is not wired, and the publish route returns 500 #110 tried to open a thread at TACC and found the page would not load at all. That is a third
instance of the class this bullet names, and the sharpest: not a key the chart omits, but a
client change shipped without its migration. Variables step cannot save any indicator: it writes a standard-variable URI into a column that references the legacy variable table #106 taughtGetThreadto read the indicator's
label; TACC'sthread.response_variablestill points at the legacyvariabletable, which has
name, and Hasura rejects the document at validation — so every thread page 500s, indicator or
no indicator. Generalise the habit rather than the instance: before the flip, walk the real
host as a signed-in user, and treat anygraphql_enginemigration not yet applied at TACC as a
live blocker until proven otherwise.
A fourth instance closed on #207, and it
reverses the direction. The first three were keys the chart omitted. This one is a key the
client's values file omits, which the chart then fills from its own default —AUTH_CLIENT_ID
rendersmint-localat TACC, and theui_reactingress rendersmint.localwith no TLS. A
chart default is a sane value, so nothing looks wrong. The rule that catches both directions:
helm templatethe client's own values file with the component switched on, and read every key
in the rendered ConfigMap against what that deployment needs. Carry BRANDING from the MINT chart to the pod at TACC #207 also retired the
BRANDINGunknown by the right method — the key is read from inside a running pod on the dev
cluster, not from the template.Flip mint.tacc.utexas.edu to ui-react #77 is again down to one blocker,
#136.
This patch is now closed. The flip ran on 2026-09-12 and the rendered config was right the
first time — the render against TACC's own values predicted the deploy exactly (one ingress
removed, fourui_reactobjects added), and the servedenv-config.jscarries all twelve
keys correctly. The rule this bullet built is what made it uneventful, so keep it for the next
deployment rather than for this one:helm templatethe client's values with the component
switched on, and read every key in the rendered ConfigMap. One addition from the flip itself:
read the servedenv-config.jsat the real host, not the template and not the pod — it is
the only artifact the browser actually runs.
Out of scope
-
Porting the un-ported Lit screens — Analysis, Emulators, Messages,
models-compare/models-calibrate/models-cromo, thread Visualize, and the 3,256-LOC
model-view. (Thread Summary was on this list in error — it is ported.) Never in the SOW,
whose scope is the config workflow and the flattened form.
T1 confirmed SUBSIDE can live without
them; it does not port them. -
Retiring
ui/entirely. Downstream of the above, and a separate effort. -
ISI's
mint.isi.educutover. Different host, different stakeholders, not this contract. -
ADR-0001 leftover debt — old
model/model_io/model_parametertables, Fuseki
references in docker-compose and CI, absent row-level security onmodelcatalog_*. -
Issue Results post-processing: indicator comparison across run ensemble #35 (results post-processing, indicator comparison across a run ensemble) — a
feature, not migration work. -
A written UAT walkthrough. Considered and declined; TACC gets the URL.
-
The same model-type fault in
model-catalog-api—
#102:/modelsreturns 44 of TACC's 55
software from a stale subtype allowlist, and fourcustom-handlers.tshandlers are cut harder
still, to 27. Real and measured, surfaced while resolving
#98. Out of scope because nothing on the path
to sign-off touches it:ui-reacttalks to Hasura directly and never calls that API (Commit .env.example and local-setup notes so ui-react runs for someone who is not Max #72 deleted
the deadMODEL_CATALOG_APIkey), and the only consumer is the Lit UI, which stays unrouted and
is being retired. Filed so it is not lost. -
A ZIP component cannot run on Tapis —
#108: the Ensemble Manager's Tapis path
JSON-parseshas_component_location, so a model whose component is alocalexZIP (HAND) fails
with an opaque 500. Surfaced on the first attempt at
#92 and proved by negative control — the
same 500, byte for byte, with the input dataset swapped. Out of scope because it is
pre-existing server behaviour, Lit hits it identically, and nothing on the path to sign-off
needs a ZIP component: Submit one thread run end to end against TACC's Ensemble Manager #92 finished by choosing a Tapis-backed model instead. It does not
block Flip mint.tacc.utexas.edu to ui-react #77. -
The Ensemble Manager rejects standard-variable indicators —
#137:POST /v1/problemStatements/*/subtasks
validatesresponse_variablesanddriving_variablesagainst the legacyvariabletable, so
after Variables step cannot save any indicator: it writes a standard-variable URI into a column that references the legacy variable table #106 it refuses every id a client can legally store. Out of scope becauseui-reactnever
calls that route — it writes threads through Hasura — and the only consumer is the Lit UI, which
stays unrouted and whose Variables screen renders zero options anyway. The inconsistency predates
the migration. Filed so it is not lost. -
Three smaller defects found while resolving Submit one thread run end to end against TACC's Ensemble Manager #92, all filed and none on the route to
sign-off. #109 — every execution row is
writtenexecution_engine: localex, including Tapis runs; the server does not read the column,
so nothing breaks today. #111 — the Runs
step prints2 runs (1 input resources × 1 parameters); the count is right and only the printed
factor is wrong. #112 — every resource with
an empty URL shares the idd41d8cd98f00b204e9800998ecf8427e, the MD5 of the empty string.
Every resource with an empty URL shares one id: the MD5 of the empty string #112 is the one to revisit if result registration ever starts writing resource rows. -
A MINT design system — TACC brand tokens across the whole app. Charted 2026-08-31 and
cut back to the chrome.ui-reactrenders the stock shadcn slate palette, and
tailwind.config.ts:14wrongly calls those slate values "TACC brand tokens (stubs)".
Repointing--primaryrecolours every button, badge and focus ring in the app, and nothing
on the path to sign-off needs that. Adopting Lit's top nav in place of the sidebar is out for
the same reason: it is a product decision, not a branding one.
The chrome half stayed in scope — a branding strip, a footer and a dark header, behind a
BRANDINGruntime key that defaults tonone
(#206).It blocks— built, carried and closed.
#77
Add the TACC branding strip, the footer and the dark header to ui-react #206 shipped the chrome inui-react; #207
carried the key through the chart anddynamoand proved it in a running pod. The flip no longer
drops the TACC and UT Austin logos thatmint.tacc.utexas.edushows today, which matters because
#80 hands the client that URL. The rest of
the design system stays out of scope.
Activity
13 remaining items