Skip to content

265 of 268 aggregations declare no metric — the engine cannot compute a value, and every one returns an empty result #1261

Description

@rubenvdlinde

265 of 268 aggregations are written in a vocabulary OpenRegister does not read

AggregationRunner::run() reads exactly nine keys off an aggregation spec.
Measured from source, not from docs:

$ grep -oE "spec\['[a-zA-Z]+'\]" lib/Service/Aggregation/AggregationRunner.php | sort -u
spec['field']  spec['filter']  spec['from']   spec['groupBy']  spec['join']
spec['metric'] spec['metrics'] spec['select'] spec['where']

metric / metrics is the only way the engine computes a value. A spec
without one returns "metric": "", "field": null and "groups": [] — an empty
result with HTTP 200, which every page renders as its own empty state and reads
as "no data yet".

Observed live on the rig, before and after removing the @self placeholder:

{"name":"byCostCenter","metric":"","field":null,"backend":"php-fallback",
 "truncated":false,"groups":[], ...}

This is #1216's first layer, unswept

#1216 had four causes
stacked on one page. The first was "the declaration spoke a grammar the engine
does not read"
— it used source and a sum list. That was fixed for one
aggregation. It is still true of 265 others.

It also explains why nobody noticed #1255's @self.administrationId problem:
these aggregations were already returning nothing for a second, independent
reason, so removing the placeholder changes an empty result into a different
empty result.

Total aggregations declared: 268
Declaring metric or metrics (the only way the engine computes a value): 3
Cannot produce a value: 265

Those that CAN:

  • CurrencyBalance.balanceByCurrency
  • CommitmentLine.committedVsRealisedPerBudgetLine
  • APInvoice.apAging

Keys the engine never reads, by frequency

key occurrences example
source 112 IBWinstOpgave.revenueExcludingVat (30-bookkeeping-ib-aangifte-zzp.json)
operations 92 IB47Record.ib47TotalsPerTaxYear (add-shillinq-detachering-payroll-administratie.json)
operation 73 Appointment.countByStatus (10-bookings-create-appointment.json)
sum 26 IBWinstOpgave.revenueExcludingVat (30-bookkeeping-ib-aangifte-zzp.json)
expression 19 StockMove.netQuantityForLocation (inventory-stock-movement-ledger.json)
type 15 CommitmentBudget.outstanding_commitments (bookkeeping-verplichtingenadministratie.json)
sourceSchema 14 GLLine.iv3DetailByTaakveldCategorie (shillinq_register.json)
label 12 ARInvoice.arAging (add-shillinq-bookkeeping-compliance.json)
register 12 ARInvoice.arAging (add-shillinq-bookkeeping-compliance.json)
schema 12 ARInvoice.arAging (add-shillinq-bookkeeping-compliance.json)
sourceRegister 10 Iv3Export.buckets (shillinq_register.json)
computedFields 7 ARInvoice.arAging (add-shillinq-bookkeeping-compliance.json)
params 6 GLTransaction.nivraBericht (add-shillinq-rekenkamer-audit-pack.json)
output 6 VpbBalansLink.vpbBalansFiltered (bookkeeping-vpb-corporate-tax-balans.json)
meta 5 GLTransaction.nivraBericht (add-shillinq-rekenkamer-audit-pack.json)
orderBy 5 APTransaction.agedPayablesDetail (bookkeeping-accounts-payable-core.json)
aggregate 5 APTransaction.agedPayablesSummary (bookkeeping-accounts-payable-core.json)
sources 5 ExpenseClaimEntry.settlementTotals (expense-reimbursement-or-passthrough.json)

What this costs

Every page reading one of these renders an empty state over live data. That is
not a hypothetical: it is exactly what #1216 was, and it took a live instance to
find, because every unit test, validator and gate was green throughout — a
test that asserts the declaration's own shape compares it to itself.

Fixing it

Each declaration needs translating into the engine's grammar with its semantics
preserved — sourcefrom, sum: [x]metric: "sum", field: "x",
operationmetric, and the operations list → metrics. Mechanical in
shape, but 265 of them, and each one's meaning has to be checked rather than
pattern-matched. It should be done in batches with a live instance to confirm
each batch actually returns rows.

Some are not translations at all and need redesign:

  • TaxEstimate.ytdByCategory declares its filter as a SQL-like string;
  • four SBRDocumentType aggregations use join.schema + join.condition (a SQL
    string) plus a check block — an entire invented sub-language.

Preventing more

tests/validate-registers.js now ratchets this: a new aggregation that declares
neither metric nor metrics pushes the count above its baseline and fails the
build. The baseline can only fall.

The alternative — implementing source/sum/operation as aliases in
OpenRegister — would make 265 declarations start working at once, with no
per-declaration check that the result is the intended one. That seems like the
more dangerous direction, but it is a real option and worth a decision rather
than an assumption.

Metadata

Metadata

Assignees

Labels

triageAwaiting triage

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions