Skip to content

Feature/clj docs - #7

Merged
bplatz merged 7 commits into
masterfrom
feature/clj-docs
Oct 27, 2020
Merged

bplatz merged 7 commits into
masterfrom
feature/clj-docs

Conversation

@bplatz

@bplatz bplatz commented Oct 27, 2020

Copy link
Copy Markdown
Contributor

No description provided.

@bplatz
bplatz requested a review from a team October 27, 2020 12:30

@cap10morgan cap10morgan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall. Might be slightly better to put all the docs stuff (including the codox dep since that's not needed at runtime) into an alias in deps.edn and invoke that from the Makefile.

@bplatz
bplatz requested a review from cap10morgan October 27, 2020 14:17
@bplatz
bplatz merged commit 336871e into master Oct 27, 2020
@bplatz
bplatz deleted the feature/clj-docs branch October 27, 2020 20:12
bplatz added a commit that referenced this pull request May 17, 2026
… diagnostics, nits

Selected items from the additional review feedback. Each call
explained.

**#1 — Retry-fragility comment on `take(opts.shapes)`.** No retry
exists on the staging path today, but `take()` moves the inline
SHACL JSON off the txn, so a future retry would silently skip
inline-shapes validation on the second attempt. Hard invariant
comment added at the move site; if retry is ever added, defer
the take until after `stage_txn` returns successfully.

**#3 — `UnsupportedFeature` errors no longer carry an empty
`ledger_id`.** `resolve_graph_ref` rejected `f:atT` /
`f:trustPolicy` / `f:rollbackGuard` *before* verifying that the
ref was actually cross-ledger, so a misrouted same-ledger ref
hitting this path would have produced a confusing error with
`ledger_id: ""`. Reordered: the same-ledger-ref guard runs first,
binding `raw_ledger_ref` once; the unsupported-feature checks
now carry the real ledger id in every diagnostic.

**#4 — `f:atT` rejection breadth: audited, no gap.** All five
`f:GraphRef`-shaped predicates already reject `f:atT` at their
same-ledger entry points:
- `policy_builder::resolve_policy_source_g_ids`
- `tx::resolve_shapes_source_g_ids` (SHACL)
- `ontology_imports::resolve_schema_bundle`
- `tx::resolve_constraint_source_g_ids_for`
- `view::fluree_ext::resolve_local_rules_source_g_id`

Plus the cross-ledger `resolver` (now with non-empty ledger_id
per #3). Audit-only change; no code modification beyond the doc
note.

**#2 — Cross-ledger policy target IRI loss is now logged.**
`wire_to_restrictions` previously `filter_map`'d unresolvable
target IRIs and `for_classes` IRIs silently. A cross-ledger
policy could quietly narrow its scope on D if M referenced IRIs
D had never registered. Two `tracing::warn!` calls now surface
both cases with `restriction_id`, requested count, and resolved
count — operators can spot the silent narrowing in logs.

Kept the restriction even when targets become empty (rather than
dropping the whole restriction): same-ledger via
`load_policy_restriction` also produces empty target sets for
the same IRI-not-in-snapshot scenario, and dropping the
restriction would diverge cross-ledger from same-ledger
semantics. The warn log is the parity-preserving signal.
`fluree-db-policy` gains a `tracing` dependency for this.

**Nits taken:**
- `TAtUnavailable` doc-commented as Phase 3 reserved (unreachable
  today because `UnsupportedFeature { feature: "f:atT" }` fires
  first).
- Empty `uniqueProperties: []` over HTTP is now documented as an
  intentional "no inline constraints" treatment, not a silent
  bug.
- Cache read/write race in `resolver` documented as benign:
  losers materialize the same value structurally; single-flight
  is a future optimization, not a correctness need.
- `f:AccessPolicy` IRI promoted from local `const` /
  duplicated-literal to `fluree_vocab::policy_iris::ACCESS_POLICY`.
  Two call sites updated; nothing else used the local consts.

**Nits skipped per "don't make changes that don't seem needed":**
- HTTP-level negative test for malformed `opts.shapes` /
  `uniqueProperties` (#5) — unit-level coverage exists; HTTP
  harness setup cost not justified.
- Same-ledger `rules_source_g_id` end-to-end test (#6) — already
  covered by `it_rules_source::rules_source_in_named_graph_is_honored`,
  which runs an actual query against the named-graph rule.
- DynamoDB hard-drop failure handling (#7) — storage layer,
  unrelated to this PR.
- Duplicate pattern match in `shapes_materializer` —
  cosmetic.
- `snapshot.ledger_id` redundancy in inline-shapes / inline-
  ontology `txn_id` — cosmetic.
- `is_last_live_branch` WARN log — unrelated path.
mwatts pushed a commit to mwatts/fluree-db that referenced this pull request Jun 12, 2026
New dedicated reference at docs/api/multi-query.md covering the
envelope contract end to end: request shape (envelope-level @context,
asOf, opts, queries map; per-sub-query language + query + opts), the
two-rule merge model (mergeable fields shallow-merge with sub-query
winning; asOf vs inner temporal pin is a hard collision), snapshot
semantics with the atomicity caveat spelled out plainly ("shared time
resolution, not distributed atomicity"), response shape with the
status / snapshot / results / errors / meta fields and the HTTP
status mapping, the bounds table, six worked examples (minimal
two-query, shared @context, mixed-language with PREFIX injection,
per-sub-query opts override, multi-ledger asOf pinning, partial
failure), and the explicit v1 limitations list (history queries,
envelope max-fuel, Tier-B cancellation, opts.t rejection).

Cross-references added so the doc is findable from the natural entry
points:

- docs/api/endpoints.md gets a POST /multi-query section with the
  envelope shape and a HTTP status table; the body of the section
  links straight to the dedicated reference for the rest.
- docs/api/README.md lists POST /multi-query in the Core Endpoints
  bullets and gets a dedicated "Multi-query envelope" subsection
  pointing to the new doc.
- docs/api/errors.md adds a callout to the 200 OK entry: "/multi-query
  returns 200 even when individual sub-queries fail; clients should
  branch on body.status." The full status mapping is linked from the
  multi-query doc.
- docs/query/README.md gets a "Bundling queries" section at the
  bottom directing users to the envelope when they have N queries
  that should share a snapshot or run in parallel.
- docs/SUMMARY.md links the new page under HTTP API.

Span / telemetry coverage:

- docs/operations/telemetry.md adds Span Tree (Multi-query envelope)
  alongside the existing Query, Transaction, Indexing, and Bulk
  Import trees; adds query:multi-query to the otel.name examples;
  documents the sub_query attribute set (alias, language,
  effective_timeout_ms, result_status) and when each is set.
- .claude/skills/trace-inspect/references/span-hierarchy.md gets a
  Multi-query envelope subsection under Query Traces with the full
  hierarchy and attribute table.
- .claude/skills/trace-overview/references/span-hierarchy.md gets the
  same envelope subsection in the more compact overview style.

CLAUDE.md docs table also gets a row pointing at the new reference
(local-only — CLAUDE.md is gitignored per repo policy).

No code changes in this commit. trace_common.py expected-children
and the it_tracing_spans.rs acceptance tests are tracked separately
under task fluree#7.
aaj3f added a commit that referenced this pull request Jul 18, 2026
resolve_join_at_open resolved EVERY GROUP BY key on the terminal dim, so a
fact-column key (#7's `GROUP BY yearNum (date dim), shipMethod (fact)`) failed
scalar_column_for_var(terminal_dim, shipMethod) and declined → 156s materialized
fold → deadline. Route each key to its single source instead: fact-column keys
read inline from the fact scan, dim-attribute keys from the FK→GKey map, composed
per SPARQL order.

- KeySource plan + assemble_group_key interleave fact-inline and dim-resolved
  positions; group_cols stays one-per-position so the output binding() is
  unchanged. Both existing paths are special cases (all-Fact = single-table,
  all-Dim = today's join, byte-identical).
- Gate Q1 (route_group_key_sources): a key's source must be EXACTLY ONE
  participating pattern — 0 (unbound), ≥2 (cross-source value-equality the fold
  cannot enforce), or an interior-dim source all decline (v1 admits fact or the
  terminal dim only). No fact-wins tiebreak.
- NULL in ANY key position drops the fact row (BGP unbound-object semantics):
  assemble_group_key's per-position Null-drop is the robust guarantee, with
  validity_cols (a fact group key is a fact object var) as the secondary drop; dim
  keys drop via the map-miss. Symmetric across sources.
- Q2 plain-literal gate applied per key on ITS OWN source pattern/TM (fact AND
  dim). O1/E2 star_constraints, #1490 dup-key decline, and the memory/cancel
  checkpoints are untouched. Empty-dim-subset (all-fact keys over a join)
  degenerates the FK→GKey map to a join-existence set.
- Hermetics: route_group_key_sources (mixed both orders, cross-source/interior/
  unbound declines, all-fact); assemble_group_key (interleave both orders,
  fact-null + dim-null drops, no-resolver defensive drop, and the empty-dim-subset
  existence-only slice `Some(&[])`).
- Corpus q066 (FACT_SHIPMENT mixed COUNT via FROM: string fact key + integer dim
  key; COUNT-only because SHIP_COST is xsd:double and the f64 SUM is
  summation-order dependent) + q067 (FACT_SUPPORT_TICKET mixed COUNT + SUM over the
  xsd:integer csatScore — exact i128, hash-deterministic — exercising the mixed key
  path together with a value fold). Oracles blessed at the wave-4 corpus gate.

Riders folded per review:
- W4-3 DEFENSIVE cancellation: values.rs ValuesOperator now polls check_cancelled
  per batch, bounding the O(input_rows × value_rows) match for a large VALUES
  product. This is capacity protection, NOT the round-3b #9 fix — #9's timeout is
  the un-lowered full scan (the VALUES→IN-set lowering is the real fix, next-slate);
  this poll only makes the execution-side product cancellable.
- W4-1: pin "-0" (parses to 0, canonical "0" ≠ "-0" → declines) and a >i64
  overflow string (parse Err → declines) in the coercion refutation hermetic.
aaj3f added a commit that referenced this pull request Sep 2, 2026
… paths

Found by an independent second adversarial pass over the shell:

- F1 (High): a FATAL re-init reply double-recycled. onmessage recycles a fatal
  reply synchronously, and the reinit .then recycled ALL non-ok replies —
  fatal included — as a microtask, arming two respawn timers. The later one
  fired an orphan worker (live wasm + SSE stream) after the first recovered,
  splitting subscriptions across two engines and leaking past close(). This
  is a flaw inside the first-round #7 remediation ("treat any non-ok re-init
  as a recycle trigger"): the correct predicate is non-fatal-non-ok. Gate the
  .then on !fatal, and make recycle() re-entrancy-safe (clear any armed
  respawn timer before re-arming).

- F2 (Medium): playground()/connect() leaked the spawned worker (and, in peer
  mode, its wasm instance) on a NON-fatal init failure — bad url, a rejecting
  getToken (401), unsupported mode — because onmessage doesn't recycle those
  and the caller never received the Channel to close it. Wrap init in
  try/catch → channel.close() + rethrow.

- F4 (Medium): a getToken that never settles wedged init forever (the worker's
  `initing` never resolves, every later op awaits it). Bound the init
  round-trip with a 30s timeout in Channel.call that rejects typed; the F2
  cleanup then closes the channel.
aaj3f added a commit that referenced this pull request Sep 3, 2026
… paths

Found by an independent second adversarial pass over the shell:

- F1 (High): a FATAL re-init reply double-recycled. onmessage recycles a fatal
  reply synchronously, and the reinit .then recycled ALL non-ok replies —
  fatal included — as a microtask, arming two respawn timers. The later one
  fired an orphan worker (live wasm + SSE stream) after the first recovered,
  splitting subscriptions across two engines and leaking past close(). This
  is a flaw inside the first-round #7 remediation ("treat any non-ok re-init
  as a recycle trigger"): the correct predicate is non-fatal-non-ok. Gate the
  .then on !fatal, and make recycle() re-entrancy-safe (clear any armed
  respawn timer before re-arming).

- F2 (Medium): playground()/connect() leaked the spawned worker (and, in peer
  mode, its wasm instance) on a NON-fatal init failure — bad url, a rejecting
  getToken (401), unsupported mode — because onmessage doesn't recycle those
  and the caller never received the Channel to close it. Wrap init in
  try/catch → channel.close() + rethrow.

- F4 (Medium): a getToken that never settles wedged init forever (the worker's
  `initing` never resolves, every later op awaits it). Bound the init
  round-trip with a 30s timeout in Channel.call that rejects typed; the F2
  cleanup then closes the channel.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants