fsanyoto commited on
Commit
dfd512f
Β·
verified Β·
1 Parent(s): 6b2a2a0

Deploy AIOS web (React glide grid + FastAPI slice)

Browse files
Files changed (3) hide show
  1. RELEASES.json +1 -1
  2. VERSION +1 -1
  3. api/routes_publish.py +20 -17
RELEASES.json CHANGED
@@ -1,5 +1,5 @@
1
  {
2
- "current": "2c4bcb5",
3
  "releases": [
4
  {
5
  "version": "v53",
 
1
  {
2
+ "current": "76fb302",
3
  "releases": [
4
  {
5
  "version": "v53",
VERSION CHANGED
@@ -1 +1 @@
1
- 2c4bcb5
 
1
+ 76fb302
api/routes_publish.py CHANGED
@@ -302,8 +302,8 @@ def _may_administer_view(session: Session, table_key: str, view_id: str):
302
  "no rows at all. Publish a copy without the cohort lock.")
303
  if _needs_a_reader(cfg.get("filters")):
304
  raise err(400, "reader_scoped",
305
- "this view filters on a cohort, a measure rule or a top-N slice, and each of "
306
- "those is resolved for the person reading it β€” a public link has no reader, so "
307
  "the page would show no rows at all. Publish a copy filtered on columns.")
308
  return view, mode
309
 
@@ -319,14 +319,18 @@ PUBLIC_ROW_CAP = 5000
319
  def _needs_a_reader(tree) -> bool:
320
  """Does this filter tree contain a leaf that only a SIGNED-IN reader could resolve?
321
 
322
- β›” COHORTS, MEASURE RULES AND RANK SLICES ARE NOT PROPERTIES OF THE VIEW. Each is a SET the
323
- host computes for the person asking β€” `filter_eval.EvalCtx`'s own docstring: *"each is an
324
- answer a single ROW cannot compute … absent, the condition matches NOTHING rather than
325
- everything"*. That default is right (it fails closed) and it is unusable here: an anonymous
326
- page whose every row was silently filtered out is indistinguishable from a broken link, and
327
- the reader has nobody to ask. Worse, `rank_sets` has NO server-side resolver anywhere in this
328
- repo β€” `routes_alerts._evaluate` passes cohort/measure/today and nothing else β€” so a `topN`
329
- view would serve zero rows on the server while showing twenty in the browser.
 
 
 
 
330
 
331
  ⭐ So such a view is refused AT THE MINT, where a person is standing in front of the answer.
332
  That is R6's second sentence: a limit that genuinely cannot be removed is REPORTED with its
@@ -346,9 +350,7 @@ def _needs_a_reader(tree) -> bool:
346
  return False
347
  if node.get("kind") == "group" or isinstance(node.get("children"), list):
348
  return any(walk(n) for n in (node.get("children") or []))
349
- if filter_eval._is_cohort(node) or filter_eval._is_measure(node):
350
- return True
351
- return node.get("op") in filter_eval.RANK_OPS
352
 
353
  return walk(tree)
354
 
@@ -561,12 +563,13 @@ def _public_view(rt, table_key: str, view: dict) -> dict:
561
  rows_src.append(r)
562
  rows_src.sort(key=lambda r: r["pid"])
563
 
564
- # The view's own row selection, through the SHARED evaluator. `_needs_a_reader` has already
565
- # refused anything this context could not answer, so an empty result here means the filter
566
- # genuinely matches nothing β€” not that we failed to resolve it.
567
  ctx = filter_eval.EvalCtx(today=time.strftime("%Y-%m-%d"))
568
  keep = set(filter_eval.visible_pids(cfg.get("filters"), rows_src, fields, ctx,
569
- member_pids=cfg.get("memberPids")))
 
570
  chosen = [r for r in rows_src if r.get("pid") in keep]
571
 
572
  # β›”β›” COORDINATES RIDE A MAP WHEN THEY ARE COORDINATES β€” NOT WHEN THEY ARE VISIBLE, AND NOT
 
302
  "no rows at all. Publish a copy without the cohort lock.")
303
  if _needs_a_reader(cfg.get("filters")):
304
  raise err(400, "reader_scoped",
305
+ "this view filters on a cohort or a measure rule, and each is resolved for the "
306
+ "person reading it β€” a public link has no reader, so "
307
  "the page would show no rows at all. Publish a copy filtered on columns.")
308
  return view, mode
309
 
 
319
  def _needs_a_reader(tree) -> bool:
320
  """Does this filter tree contain a leaf that only a SIGNED-IN reader could resolve?
321
 
322
+ β›” COHORTS AND MEASURE RULES ARE NOT PROPERTIES OF THE VIEW. Each is a SET the host computes
323
+ for the person asking β€” `filter_eval.EvalCtx`'s own docstring: *"each is an answer a single
324
+ ROW cannot compute … absent, the condition matches NOTHING rather than everything"*. That
325
+ default is right (it fails closed) and it is unusable here: an anonymous page whose every row
326
+ was silently filtered out is indistinguishable from a broken link, and the reader has nobody
327
+ to ask.
328
+
329
+ ⭐ Rank slices are deliberately NOT included. `filter_eval.visible_pids` resolves their
330
+ membership from the server row payload before evaluating it, so a public `topN`/`bottomN`
331
+ link has one deterministic answer independent of its reader. `evaluate` remains fail-closed
332
+ for a bare row context; this route takes the whole-payload entry point precisely so it can
333
+ answer the set question rather than silently publish an empty page.
334
 
335
  ⭐ So such a view is refused AT THE MINT, where a person is standing in front of the answer.
336
  That is R6's second sentence: a limit that genuinely cannot be removed is REPORTED with its
 
350
  return False
351
  if node.get("kind") == "group" or isinstance(node.get("children"), list):
352
  return any(walk(n) for n in (node.get("children") or []))
353
+ return filter_eval._is_cohort(node) or filter_eval._is_measure(node)
 
 
354
 
355
  return walk(tree)
356
 
 
563
  rows_src.append(r)
564
  rows_src.sort(key=lambda r: r["pid"])
565
 
566
+ # The view's own row selection, through the SHARED whole-payload evaluator. It resolves rank
567
+ # sets from `rows_src` before evaluating, while `_needs_a_reader` has already refused the
568
+ # cohort/measure leaves this anonymous context cannot answer.
569
  ctx = filter_eval.EvalCtx(today=time.strftime("%Y-%m-%d"))
570
  keep = set(filter_eval.visible_pids(cfg.get("filters"), rows_src, fields, ctx,
571
+ member_pids=cfg.get("memberPids"),
572
+ group_by=cfg.get("groupBy")))
573
  chosen = [r for r in rows_src if r.get("pid") in keep]
574
 
575
  # β›”β›” COORDINATES RIDE A MAP WHEN THEY ARE COORDINATES β€” NOT WHEN THEY ARE VISIBLE, AND NOT