Repository navigation
Releases: bgarcevic/tomix
Release list
v0.13.0
Added
tx deploychecks the deployed model after it lands: it re-reads the target and reports every
object the server holds in an error, incomplete, or unprocessed state, in the text output and
asvalidationin the JSON result. Objects in an error state (a measure whose DAX does not
resolve, a broken RLS filter) fail the deploy with exit code 1 and
TOMIX_DEPLOY_VALIDATION_FAILED, even though the model is deployed; incomplete objects warn
(TOMIX_DEPLOY_VALIDATION_WARNINGS); unprocessed ones point attx refresh. A check that
cannot run warns withTOMIX_DEPLOY_VALIDATION_UNAVAILABLE.--ci vsts|githubnow prints
annotations for post-deploy errors and warnings.tx deploy --rollback-on-errorchecks the deployed model before the deploy is kept. On an
existing model the deploy runs inside a server transaction and rolls back when an object is in
an error state, leaving the target's definition and data unchanged. A new model is deleted
again. A rolled-back deploy fails withTOMIX_DEPLOY_ROLLED_BACKand"status": "rolled-back".
See ADR 0005.tx formatstyle options (#229):--separators us|eushows DAX with;list and,
decimal separators (display only; models always store the US form, and an explicit
--separators euwith--save,--save-to,--stageor--revertfails with the new
TOMIX_FORMAT_SEPARATORS_DISPLAY_ONLY),--function-spacing space|nonedrops the space
before a DAX call's parenthesis, and--shortundoes--long. Each has a config key
(format.separators,format.functionSpacing,format.lines) that the flag overrides.
Golden files pin the printed output for each style.tx bpa run --vpax <file.vpax>reads VertiPaq statistics from a file exported with
tx vertipaq --export, so statistics rules run on a model file, a read-only connection, or in
CI without annotating the model. The statistics apply in memory only. A file that matches no
table fails the run (TOMIX_BPA_VPAX_MISMATCH); tables missing from the model warn
(TOMIX_BPA_VPAX_PARTIAL) (#234).- New default-off
vertipaqruleset preset with every bundled rule that reads statistics,
including two new rules:LARGE_SHARE_OF_MODEL_SIZEand
UNUSED_HIDDEN_HIGH_CARDINALITY_COLUMNS. Rules can read model-level annotations through
Model.GetAnnotation(...)(#234).
Changed
FIX_REFERENTIAL_INTEGRITY_VIOLATIONS,AVOID_BI-DIRECTIONAL_RELATIONSHIPS_AGAINST_HIGH-CARDINALITY_COLUMNS
andLARGE_TABLES_SHOULD_BE_PARTITIONEDmove to thevertipaqpreset (categoryVertiPaq),
out ofstandardandfull.bpa runwithout--rulesetand thedeployBPA gate add the
vertipaqpreset when the model has statistics (Vertipaq_*annotations or--vpax), so an
unannotated model no longer lists them as "Not checked". A named--rulesetis used as given:
--ruleset standardnow skips them (#234).
Fixed
tx test --tolerance(andtx: tolerance=) now applies to measures whose data type is Variant.
Their results read back asobjectcolumns, which compared exactly, so floating-point noise
failed the test whatever the tolerance. Cells compare within the tolerance when both sides are
numbers; text, dates and booleans still compare exactly.--ignore-row-ordersorts these
columns by value after the dimension columns, in a fixed BLANK, number, text order.
What's Changed
- feat(bpa): read VertiPaq statistics from .vpax and add a vertipaq preset by @bgarcevic in #464
- feat(format): style options for separators, function spacing, and line length by @bgarcevic in #465
- feat(deploy): post-deploy validation reporting in result and JSON by @bgarcevic in #467
- build: Bump the nuget-minor-patch group with 7 updates by @dependabot[bot] in #468
- feat(deploy): --rollback-on-error validates inside a transaction and rolls back by @bgarcevic in #469
- fix(test): apply tolerance to Variant (object) measure columns by @bgarcevic in #471
- chore(release): prepare 0.13.0 by @github-actions[bot] in #466
Full Changelog: v0.12.1...v0.13.0
v0.12.1
Fixed
- Sign-in and tx's own HTTP requests no longer hang on networks that advertise IPv6 they cannot
route: connections race IPv6 and IPv4 the way browsers do (Happy Eyeballs), sotx auth login
falls back to IPv4 within a quarter of a second instead of timing out. A spinner waiting on a
remote host (auth login, connect, deploy, query) now says which host after 10 seconds and that
Ctrl+C cancels.
What's Changed
- chore: rename repository to tomix by @bgarcevic in #461
- fix(net): race IPv6 and IPv4 so broken-IPv6 networks don't hang sign-in by @bgarcevic in #462
- chore(release): prepare 0.12.1 by @github-actions[bot] in #463
Full Changelog: v0.12.0...v0.12.1
v0.12.0
Added
tx rmremoves several objects as one change: pass several paths, or--from <file|->with
JSON Lines ({"type", "table"?, "name"}or{"path"}) or plain paths. Every kindrm
supports can be mixed. All targets resolve before anything changes, the dependency guard
judges the whole set regardless of order, targets inside another target are folded into it,
and cascades onto surviving objects need--cascade. One validation, one save, one undo step.
New error codesTOMIX_RM_NEEDS_CASCADEandTOMIX_RM_INPUT_INVALID.tx rmrefuses to remove a shared expression that surviving Power Query (M) still reads (M
partitions, other shared expressions, refresh policy queries), using the bundled M parser.
JSON addsbrokenMReferences;--forceoverrides.tx validatechecks Power Query (M) partition sources and shared expressions offline with
the bundled M parser, and reports each one that does not parse as anM0001error with its
line and column.--no-m(MCP:"m": false) skips the check (#453).tx test --tolerance <value>accepts numeric cells within an absolute difference (0.001) or a
percentage of the larger value (0.1%), so floating-point noise in averages and ratios no
longer fails a test.--ignore-row-ordersorts both rowsets before comparing, so test queries
need noORDER BY. A test overrides either option in a// tx:comment line before its query
(// tx: tolerance=0.01% ignore-row-order); an unknown directive fails the test.tx test --update-missingrecords snapshots only for tests that have none yet and compares the
rest, so adding a test no longer means re-accepting the whole suite.tx test --updatenow lists
what it accepted: each rewritten snapshot shows a Before/After table of the cells that changed
(differencesin JSON). Snapshots left behind by a deleted or renamed test are reported as
orphans (orphansin JSON) without failing the run (#451).- A BPA fix expression can assign a quoted string literal as written, with
\"and\\
escapes, so a model-provided rule can set DAX (Expression = "DIVIDE([A], [B])"). An
unquoted value with(or[is still an unsupported fix expression (#208).
Changed
tx testsnapshots (.expected.json) are written with one column and one row per line, so a
changed value diffs as its whole row instead of a bare value. Existing snapshots still load;
the next--updaterewrites them in the new layout without changing their content.tx get <object> --output-format tmdl|bim|tmslprints the object through the model's own
serializer instead of a hand-built skeleton, so fragments keep descriptions, format strings,
display folders, lineage tags, annotations and child objects. A TMDL table child is wrapped in
ref table <name>and pastes into its table's.tmdlfile as is. Relationships, roles,
hierarchies, functions and the other kinds print as fragments instead of the property view,
andtx get .prints the whole model. A model source without a serializer fails with
TOMIX_SCRIPT_UNSUPPORTED(#243).- The
tx bpa run --fixpreview groups pending fixes by rule and shows a property change once
over every object that gets it (IsHidden: false → trueover a list of columns, capped at 10
unless--full), quoting only text values. An expression fix shows full Before/After blocks,
DAX syntax-highlighted in a terminal and plain when piped, capped at 12 lines each, instead of
one line cut at 60 characters (#208). - A BPA finding is marked fixable (
canFixin JSON) only when tx can run its rule's fix
expression. Under--fix, a rule whose fix tx cannot run (such as
Partitions[0].Name = it.Name) is listed once with its finding count (unsupportedFixesin
JSON) instead of adding one "Unsupported fix expression" fix error and one skip per object. tx connect -wchecks whether the workspace target already exists by listing the workspace's
models instead of downloading the target's whole model, so the step after the model picker is
fast on large models. A dataset that the list hides but that exists (read-only access) is still
reported instead of being treated as a new mirror (#142).
Fixed
- A lone
[Col]in DAX resolves to the tables DAX can bind it to, instead of the first table
with a column of that name: the innermost table iterated around it that has the column
(SUMX('Fact A', [Revenue])reads'Fact A'[Revenue], even in a measure of a table with its
own[Revenue]), and the expression's own table (SUM([Revenue]), a calculated column's row).
tx rmno longer refuses to removeSales[Date]becauseDateTableTemplate'sYEAR([Date])
reads its ownDate, andtx depsand rename fixups follow the right columns. Where the
binding is unknown (a table expression without a rule,EARLIER), every table's column of that
name still counts, so a removal blocks rather than breaking a reference. - BPA follows the same rule:
ReferencedBycounts a lone[Col]only for the tables it may bind
to, so a deadSales[Date]is no longer kept alive byDateTableTemplate'sYEAR([Date]), and
theDAX_COLUMNS_FULLY_QUALIFIEDfix qualifies such a reference with the one table DAX binds it
to instead of refusing because other tables share the name. It still refuses when two tables
remain possible. tx validatejudges a lone[Col]by the tables DAX can bind it to; it used to pass if any
table had the column. Outside every iterator, in a measure, calculated column or role filter, a
column only another table has is a newDAX0010error (DISTINCTCOUNT([Region])in aSales
measure when onlyGeohasRegion), which DAX rejects too. Inside an iterator that does not
provide it, it is aDAX0003warning. Window functions'ORDERBY/PARTITIONBYcolumns count
as rows of their relation. Both messages name the qualified columns to use instead.- Help for subcommands such as
tx stage commit,tx auth login,tx config setand
tx skills installnow shows anExamples:block. Thetx auth loginservice-principal example
uses-ufor the app id instead of--client-id. The reference docs list every shipped option,
includingformat --type,save --no-syncand thebpa runstaging flags, and no longer show
-p/-taliases thattx auth logindoes not have (#148).
What's Changed
- feat(get): emit TMDL, BIM and TMSL through the TOM serializer by @bgarcevic in #449
- feat(validate): report Power Query (M) syntax errors offline by @bgarcevic in #455
- feat(test): numeric tolerance and order-insensitive comparison by @bgarcevic in #454
- feat(test): safer snapshot recording with --update-missing, accepted diffs and orphans by @bgarcevic in #456
- perf(connect): classify the mirror target from the database list by @bgarcevic in #457
- docs: guard option-level drift and add subcommand help examples by @bgarcevic in #459
- feat(bpa): grouped --fix preview with highlighted DAX before/after by @bgarcevic in #458
- feat(rm): batch removal with whole-set guard and Power Query references by @bgarcevic in #460
- chore(release): prepare 0.12.0 by @github-actions[bot] in #450
Full Changelog: v0.11.0...v0.12.0
v0.11.0
Added
tx querychecks the tables, columns and measures a DAX query names before sending it. A
typo fails at once withTOMIX_QUERY_UNKNOWN_REFERENCEand the closest name
(Did you mean 'Amount'?), or the table's columns or the model's tables when nothing is
close, instead of a server error. Names the query defines itself are understood;
--no-validateskips the check (#240).tx query --coldreportsTOMIX_QUERY_COLD_UNAVAILABLEwhen it cannot clear the cache, and
--tracereportsTOMIX_QUERY_TRACE_UNAVAILABLEwhen it cannot capture server timings, so
the JSON output says so too, not only a stderr line.
Changed
- Edits and undo in a live session (
tx shell,tx serve,tx mcp,tx ui) are faster on
large models: the session copies the model for the next undo step in the background after
each edit instead of during it. On a model with 1,000 measures an edit drops from about
100 ms to about 50 ms and undo from about 55 ms to about 30 ms (#423). - The undo history of a live session is capped by model size as well as by count, so a large
model keeps fewer than 50 steps and the session's memory stays near 250 MB (#423). - Text output uses color more sparingly. Labels in key-value blocks (
auth status,doctor,
diff,connect,validate,vertipaq, …) are plain instead of bold, with the values lined
up in one column. Progress lines and notices such as "Authenticating..." and where
credentials were saved are dim. Placeholders in--help(<path>,[options]) are dim too
(#440). - With stdin piped (
$secret | tx auth login --password -), a command's progress label prints
once, dim, on stderr instead of as plain text on stdout (#440).
Fixed
-
tx queryandtx testwork with read access only (the Viewer role with Build permission).
They used to fail withDatabase not found, because the server lists only the models a
caller can write to. Commands that read the model's metadata now fail withTOMIX_METADATA_ACCESS_DENIED
instead, naming the write access they need. The docs no longer say--traceand--cold
need admin rights: write access (workspace Admin, Member or Contributor) is enough. -
A wrong model name on a Power BI workspace fails with
TOMIX_DATABASE_NOT_FOUNDinstead of
TOMIX_CONNECT_FAILEDand a raw(404) Not Found. -
tx validatechecks each row-level security filter on its own table permission
(Roles/<role>/<table>). It used to parse a role's filters joined asTable: <filter>lines,
so a role with more than one filter could fail withUnexpected ':' after the end of the expression(DAX0007). Renaming a column or table now rewrites the RLS filters that use
it instead of only warning, and BPA rules see filters that span several lines whole. -
tx validate,tx depsand rename fixup also cover calculation group no-selection and
multiple-or-empty-selection expressions and calculation item format string expressions. -
tx bpa runchecks rules scoped toTablePermission, which it used to skip: the dynamic RLS
rule (fullruleset) now reports roles that filter onUSERPRINCIPALNAME()orUSERNAME(),
andDAX_COLUMNS_FULLY_QUALIFIEDchecks RLS filters, with--fixqualifying their column
references. A permission is reported as<role>/<table>. -
Reference tracking (
deps,validate, rename and remove guards, BPA) now reads DAX with the
same lexer astx formatanddax check, so a date literal (dt"2024-01-01") or a query
parameter (@Risk) is no longer taken for a table nameddtorRisk(#204). -
The
tx deploypreview no longer reports a calculated column as modified when its source
has nodataType(as Power BI Desktop writes it) and the deployed model holds the type the
engine inferred, for exampledatetime, calculatedtounknown, calculated. -
A modified object in
tx diffand thetx deploypreview now prints as
~ CalculatedColumn Calculations/Date: DataType, so the changed property no longer reads as
part of the object's name (Calculations/Date Detail). A column's type change is labelled
DataTypein text output; JSON keepsDetail. -
-s/--serverandtx connectnow reach an on-premises Analysis Services server as typed
(ssas01.contoso.com,10.0.0.5,ssas01:2383,ssas01.contoso.com\TABULAR, or a full
MSOLAP connection string) with your Windows identity, instead of prefixing it with
powerbi://api.powerbi.com/v1.0/myorg/and sending the deploy to Power BI.deploywarns
(TOMIX_DEPLOY_AMBIGUOUS_SERVER) when a dotted two-part name such asSales.Prodcould also
be a workspace name.
What's Changed
- fix(validate): check each RLS filter on its table permission by @bgarcevic in #448
- chore(release): prepare 0.11.0 by @github-actions[bot] in #447
Full Changelog: v0.10.0...v0.11.0
v0.10.0
Added
-
tx mcpserves a model session to AI agents (Claude Code, Codex, Cursor and others) as Model
Context Protocol tools on stdio:claude mcp add tomix -- tx mcp. Each tool calls the session
protocol method of the same name, so an agent's edit is one undo step, and
transaction_begin/transaction_commitgroup several under a label. Whentx uiholds the
model,tx mcpjoins that session, so you watch, undo and save the agent's work in the page.
Every tool says whether it writes (readOnlyHint,destructiveHint), and--read-onlylists
only the ones that change nothing (#354). The server tells the agent to save a TMDL folder or
.bimfile once its checks pass, and to ask before saving to a server or Power BI Desktop. -
tx skills install,status, anduninstallinstall the tomix agent skill for Claude Code
(.claude/skills/tomix) and Codex and other Agent Skills harnesses (.agents/skills/tomix),
in the repository or with--userin your home folder. The skill ships inside the binary, so it
matches the installedtx.statusreports copies from another version as outdated, and copies
that were edited or not written by tx are left alone unless you pass--force
(TOMIX_SKILL_CONFLICT). The skill covers live sessions too: edit through thetx mcptools
rather than the files while a session is open. A new guide, "Using tomix from your agent",
covers setup, including watching an agent's edits intx ui(#404). -
A client of a live session (
tx serve,tx ui) can ask ininitializefor
capabilities.diagnostics. The host then recomputes dependencies, DAX diagnostics and,
with{ "bpa": true }, BPA findings 250 ms after the last change and sends
diagnostics.updated;dax.checkandbpa.runanswer from those results.deps.get,
dax.checkandbpa.runnow read the last committed version instead of waiting for
another client's transaction (#350). -
A live session (
tx interactive,tx serve,tx ui) on a TMDL folder or.bimfile now
notices when the files change outside it, for example by agit checkoutor another editor.
The session turnsstale, and saving fails withTOMIX_SESSION_STALEinstead of overwriting
that change.reload(protocol:session.reload) takes the files' version, and
save --force(session.savewithforce) keeps the session's. Thetx uipage offers
both (#351). -
A live session on a server or Power BI Desktop now notices when the model changes there
outside it (checked every 10 seconds for Desktop, 30 for a remote server): it turnsstale, andsavefails with
TOMIX_SESSION_STALEuntilsave --force.session.statusreportscanReload(#351). -
A live session whose Power BI Desktop has closed fails with
TOMIX_SESSION_SOURCE_UNAVAILABLEinstead of a raw connection error;save -o <folder>
still writes its changes to files. The shell,status(protocol:sourceUnavailable) and
thetx uipage say so as soon as a check finds it gone (#351). -
tx refreshon a PBIP's files (the.pbip, its.SemanticModelfolder, or anything in it)
now refreshes the model in the Power BI Desktop that has that PBIP open, as Tabular Editor
does, instead of failing withTOMIX_REFRESH_NO_REMOTE_TARGET. It says so with
TOMIX_REFRESH_IN_DESKTOP.
Changed
txnow colors its output with your terminal theme's own ANSI colors instead of a fixed
RGB palette, so it matches Campbell, Dark+, Solarized, high-contrast and color-blind-friendly
themes. Color is kept for status (red, yellow, green) and DAX and M highlighting; names,
paths and values print plain, options bold, and secondary text dimmed. DAX keywords are
magenta, functions bright blue, measure references cyan, and literals green; tables,
columns and variables are no longer colored. Help section headings are bold and
uppercase (USAGE,DISCOVER), and the command and option names under them regular weight. Thetx uipage moves to warm neutrals with a single persimmon accent.
Fixed
savein a live session on a server or Power BI Desktop sends the changes to the server
instead of failing withTOMIX_SAVE_OUTPUT_REQUIRED, andsave -onaming the session's own
files saves in place, so it no longer skips the check for changes made outside the session
(#351).- A command on a Power BI Desktop that has closed fails at once with
TOMIX_DESKTOP_NOT_RUNNING
and a hint to reopen it, instead of waiting about 4 seconds for a raw socket error.
Opening a session (tx interactive,tx serve,tx ui) there, or on a server it cannot
reach, reports the connection error instead of "Unexpected error" (#351). - Tables written to a pipe or a file no longer wrap at 80 columns, and use ASCII borders
(+,-,|) instead of box-drawing characters, as dotx deps --deeptrees. A DAX
expression or format string intx lsoutput stays on one row, so it can be grepped or read
by an agent, and borders no longer turn into mojibake in Windows PowerShell 5.1 ormore.
tx bpa runandtx bpa rulesswitch their symbols to ASCII there too (*for●,x
for×,-for·and—,OK/FAILfor✓/✗).
What's Changed
- feat(session): notice files changed outside a live session; reload or keep (#351) by @bgarcevic in #403
- feat(refresh): refresh a PBIP in the Power BI Desktop that has it open by @bgarcevic in #407
- feat(session): notice server-side changes in a live session; clear error when Desktop is gone (#351) by @bgarcevic in #406
- feat(session): recompute deps, DAX diagnostics and BPA after changes (#350) by @bgarcevic in #415
- feat: agent skill, plain redirected output, and the ANSI terminal palette by @bgarcevic in #416
- feat(mcp): tx mcp, an MCP server over the live session (#354) by @bgarcevic in #417
- feat(output): terminal ANSI palette, ASCII BPA symbols when redirected, uppercase help headings by @bgarcevic in #418
- feat(skill): cover live sessions, and let agents save file models by @bgarcevic in #419
- chore(release): prepare 0.10.0 by @github-actions[bot] in #405
Full Changelog: v0.9.0...v0.10.0
v0.9.0
The live session (tx interactive, tx serve, tx ui) is a preview: its protocol and options
may still change. A live session does not yet notice when other tools change its model's files
(for example a git checkout or an edit in Power BI Desktop), and saving from it overwrites
those changes; save or close the session before changing the files another way (#351).
Added
tx interactive(aliastx shell) opens a model once and keeps it in memory: commands such
asget,set,add,rmandbpa runwork on the open model,undoandredostep
through every change,begin…commitgroups edits into one undo step,historylists
them, andsavewrites the model. It asks before discarding unsaved changes (#347).tx serveholds a live session for editors and agents and speaks the tomix session protocol
(JSON-RPC over stdio, specified indocs/protocol.md): open, read, edit, undo, transactions,
save, and change events for every client (#348, #349).tx ui [model]shares a live session on127.0.0.1with a browser page and agents at the
same time: the page shows who is connected and every client's changes as they happen, with
Undo, Redo and Save.--openopens the page;--port,--graceand--logtune it. Every
request needs the session's token.tx serveon a modeltx uiholds joins that session
instead of opening a second one (#369).- While
tx uiholds a model,add,bpa run,deps,find,format,get,ls,mv,
replace,rm,save,set,summaryandvalidateon it run in its session instead of
on the files: edits become undo steps there and show up on the page, reads see unsaved
edits, and edits stay unsaved untiltx save(#400). - New error codes
TOMIX_SESSION_IN_USE,TOMIX_UI_UNAUTHORIZED,TOMIX_UI_FORBIDDEN,
TOMIX_UI_PORT_IN_USEandTOMIX_UI_UNREACHABLE(#369).
What's Changed
- feat(core): live session contracts and ADR 0002 lease gate (#343) by @bgarcevic in #380
- feat(provider-tom): change journal and TomWriter for every TOM write (#379) by @bgarcevic in #381
- feat(provider-tom): TomLiveModelSession with a FIFO lease gate (#344) by @bgarcevic in #382
- refactor(app): run handlers against an open session (#345) by @bgarcevic in #384
- feat(provider-tom): undo, redo and explicit transactions in the live session (#346) by @bgarcevic in #385
- feat(cli): tx interactive (alias tx shell), the live session REPL (#347) by @bgarcevic in #386
- docs(protocol): tomix session protocol v0 spec (#348) by @bgarcevic in #387
- feat(serve): tx serve over stdio (#349) by @bgarcevic in #389
- ci(dependabot): use conventional dependency update titles by @bgarcevic in #388
- feat(serve): one live session shared by several clients over localhost (#369) by @bgarcevic in #390
- build: Bump Microsoft.CodeAnalysis.BannedApiAnalyzers from 4.14.0 to 5.6.0 by @dependabot[bot] in #383
- feat(ui): tx ui shares a live session with a browser page and agents (#369) by @bgarcevic in #399
- feat(live): one-shot commands on a model tx ui holds run in its session (#400) by @bgarcevic in #401
- chore(release): prepare 0.9.0 by @github-actions[bot] in #402
Full Changelog: v0.8.0...v0.9.0
v0.8.0
Added
tx getis now the single read command. A path naming one object shows its properties; a
wildcard ("Sa*"), a container (Sales/Measures), or no path lists every match. New options
select and analyze over the same path resolution:--ls,--where Prop=Value
(case-insensitive,*wildcard, repeat to AND),--deps [upstream|downstream]with--deep
and--max-depth,--unusedwith--hidden,--paths-only, and--no-multiline.tx ls
andtx depskeep their flags and are now shortcuts forget --lsandget --deps/
get --unused, with identical output (#335).- BPA rule sources beyond
--rules: thebpa.rulesconfig key and theTOMIX_BPA_RULES
environment variable add team rule files tobpa run,bpa rules list/show/ignore, and
thedeployBPA gate.bpa runprints a "Rules loaded" line saying where every rule came
from and how many a later source overrode (JSON:ruleSources) (#233). --rulesetpresets for default-off rule categories (for examplelocalization), which
neitherstandardnorfullincludes. Repeat--rulesetor comma-separate it to combine
presets (#233).tx bpa rules ignore --userandunignore --userturn a rule off (or back on) just for you,
on this machine, for every model; without--userthey still write the model's ignore
annotation.bpa rules list --ignoredshows rules ignored at either level, andbpa run
says which level ignored a rule (JSON:userIgnoredRules).unignorewarns when the other
level still ignores the rule (TOMIX_BPA_RULE_STILL_IGNORED_BY_MODEL,
TOMIX_BPA_RULE_STILL_IGNORED_BY_USER) or when the rule isn't in the ruleset that runs
(TOMIX_BPA_RULE_NOT_IN_RULESET) (#233).
Changed
- Breaking:
tx sessionis removed;tx connectcovers it.tx connectnow names the
session holding the connection (JSON: asessionobject withid,kind,scope,path),
tx connect --clearreplacessession clear, andtx connect --clear --allforgets the
connection in every session.session pruneandsession listhave no replacement: each
tx connect <target>now removes session files whose folder no longer exists (and legacy
pid-*sessions of exited shells), andtx doctorreports any stale ones left. - Breaking:
tx deployand the partition-riskytx refreshvariants (--refresh-type clearvalues,--skip-refresh-policy,--effective-date,--policy-only) preview by
default. Each shows its preview (the deploy diff, or the refresh TMSL or policy-only
summary), then asks before applying. The preview and the apply share one connection, so
the model opens and the deploy BPA gate runs once.
Where it cannot prompt (--non-interactive,--quiet, JSON or CSV output, redirected input)
it stops after the preview and exits with the new exit code3, instead of failing with
TOMIX_CONFIRMATION_REQUIRED. Pass--yesto apply without the preview. Routine refreshes
still run without asking.deploy --xmlaonly writes a script, so it no longer asks. - Breaking:
tx bpa run --fixwithout--save,--save-to, or--stageis a preview: it
lists each pending fix with before and after values, reportsfixesApplied: 0, and judges the
exit code on the model as it is. tx rm,tx replace, andtx bpa run --fix --allow-deleteask for confirmation only when
they write (--save,--save-to,--stage, or--revert). A preview no longer asks. A
preview ofrmon an object that DAX still references reports the dependents and hints
--forceinstead of failing.- Breaking: JSON output says
previewwhere it saiddryRun: mutation results drop the
dryRunfield and thedryRunstatus (statusispreview),bpa runreportspreview
instead ofdryRun, anddeployreportsstatus: "preview"instead of"dry-run". Therefresh --policy-onlypreview's
CSV columndry_runis nowpreview. tx get Measuresand other bare container paths now list the container instead of failing
withTOMIX_OBJECT_NOT_FOUND, andtx get ./modellists the model's tables.--queryor
--depson a path that selects a set fails withTOMIX_SINGLE_OBJECT_REQUIRED(#335).tx bpa rules listshows each rule ID once, from the source that wins as inbpa run, and
says what a team or model rule overrides (JSON:overrides);bpa rules showstill prints
every source's copy. Without a model,listandshowuse the active local connection (#233).tx bpa rules disableandenableare hidden; they still work and do the same as
ignore --userandunignore --user(#233).- Internal:
validateandbparules now share one rule shape and one severity scale, and every
validateissue code comes from a documented rule catalog. Output is unchanged (#230).
Fixed
- A quoted folder path with a trailing backslash, such as
tx connect '.\My Model.SemanticModel\'
in Windows PowerShell 5.1 or".\My Model.SemanticModel\"in cmd.exe, no longer fails with a
stray"at the end of the path. Windows reads\"as a literal quote;txnow restores the
path when the text before the quote is an existing folder. tx formatandtx addno longer wait on stdin when it is redirected but nothing is piped,
as in a CI step, an ssh session, or a script whose parent holds stdin open.formatreads a
piped expression only when no model,--path,--save,--save-to,--stage, or
--revertis given, sotx format ./model --saveno longer blocks or formats stray stdin
instead of the model.addreads stdin only for-e -, as documented; a bare pipe into
addis no longer read.tx querystill reads a piped query when none is given.tx deploywithout-dnow previews the database it would actually write (named after the
model) instead of skipping the diff and showing the model path as the target. A model with no
name of its own, such as a bare TMDL folder, fails withTOMIX_DEPLOY_NO_TARGETasking for
-dinstead of a serializer error.
Removed
- Breaking:
--dry-runis removed from every command (add,set,mv,rm,replace,
format,bpa run,deploy,refresh,session prune). Model edits already preview unless
you pass--saveor--stage, and the commands that change a target now preview by default.
TheTOMIX_BPA_DRY_RUN_REQUIRES_FIXcode is gone with it. - Breaking:
tx init,tx config init,tx bpa rules init, andtx connect -wtake
--overwriteinstead of--forceto replace an existing target, matching--overwriteon the
save commands.--forcenow only ever bypasses a check. Recover a corrupt config withtx config init --overwrite. - Breaking:
tx deploy --forceis removed. It never had an effect: no deploy check read it.
Use--skip-bpato bypass the BPA gate.
What's Changed
- feat(get): make get the single read pipeline; ls and deps become shortcuts by @bgarcevic in #335
- chore(agents): remove template dotnet skills that contradict repo conventions by @bgarcevic in #337
- feat(connect)!: fold tx session into tx connect by @bgarcevic in #339
- feat!: preview by default instead of --dry-run by @bgarcevic in #338
- docs(design): ADR 0001 for the live model session by @bgarcevic in #373
- feat(bpa): rule-source chain, attribution, default-off presets, and ignore --user (#233) by @bgarcevic in #340
- fix(cli): don't block on a redirected stdin that nothing was piped into by @bgarcevic in #375
- refactor(rules): share one rule shape across validate and bpa by @bgarcevic in #376
- fix(cli): repair quoted Windows paths with a trailing backslash by @bgarcevic in #377
- chore(release): prepare 0.8.0 by @github-actions[bot] in #336
Full Changelog: v0.7.0...v0.8.0
v0.7.0
Added
tx bpa rules add,set,remove, andinitauthor custom BPA rules from the CLI. They edit
your config-dirbpa-rules.json(whichbpa runloads) or the file--rules-filenames, and
keep fields tx does not model. Scope and severity are validated (#232).tx bpa rules add,set, andremovetake a model to edit the rules that ship with it, in
itsBestPracticeAnalyzerannotation. The edit runs like other model mutations (--save,
--stage,--save-to, ...), uses the same field checks as rules files, and keeps fields tx
does not model (#330).tx bpa run --fixnow fixesDAX_COLUMNS_FULLY_QUALIFIEDandDAX_MEASURES_UNQUALIFIED
by rewriting the object's DAX, through two new fix expressions:
QualifyColumnReferences()andUnqualifyMeasureReferences(). References that cannot be
resolved for certain (a column name in several tables, a name that is also a string literal,
a measure qualified with the wrong table) are reported as fix errors and left unchanged (#267).tx doctorreports the current session's connection (current-session) and, on Windows,
warns when you are signed in but the token cache file is missing.tx doctor --show-detailsincludes account, server, database, model, profile, and session
names and full paths. Without it, the report is safe to paste into a bug report: the home
directory is shown as~and names are replaced by what kind of thing they are.tx doctorsuggeststx session prunewhen session files of exited shells are left over.
Changed
tx doctoroutput is shorter and only warns when something needs doing. Optional states
(no profiles, not signed in, no update check yet) are reported with the newInfostatus
(INFO) instead ofWARN. Theruntime,operating-system,terminal, and
model-providerschecks are removed because they could never fail; the runtime, OS, and
terminal details are still in the header and in the JSON fields. Theupdate-cachemessage
now shows a short UTC time and says to runtx update. A source build (./tx) or an install
tx updatecannot update reports a newer release asINFOwithout that hint, matching the
update notice. The header and JSON (installKind) show how tx was installed.tx doctorno longer prints the end-of-command "a new version is available" notice (its
update-cachecheck already says so) and no longer refreshes the update cache over the
network, keeping its promise to stay local.tx doctorno longer creates~/.tomixon a machine where tx has not run yet; it reports
that the directory will be created on first use.tx gettext output shows only the properties that are set, aligned under the object's path
and kind, with annotations and translations in their own sections and multi-line expressions
as indented blocks. Unset settable properties fold into oneNot set:line, followed by a
tx sethint. The new--alloption lists every property, with a "N of M set" count, a dim
—for empty values, and aread-onlytag. JSON and CSV output are unchanged.tx get --querywith an unknown property now fails withTOMIX_PROPERTY_NOT_FOUNDand
suggests the closest property name, or lists the valid ones when nothing is close. An unset
annotation:ortranslation:token reads back as null.
Changed
tx bpa rules listshows each rule's scope, and lists the rules in your config-dir
bpa-rules.json(sourceuser), matching whatbpa runloads (#232).- Config, profiles, recent connections, session, staging, update-check, auth, BPA, and
test-snapshot files are now read and written with source-generated JSON instead of runtime
reflection, as groundwork for a faster-starting Native AOT build. The files' format is
unchanged, so existing ones keep working. - Release binaries and the
dotnet toolpackage no longer includemsalruntimeand
msasxpress, two native libraries tx never uses for sign-in (the release binary is about
3 MB smaller). Thedotnet toolpackage now talks to XMLA endpoints uncompressed, as the
release binaries already did.
Removed
- Breaking:
tx scriptis removed. Despite its description it never ran C#: it evaluated a
handful of fixed read-only expressions (Model.Tables.Count,Model.Tables[0].Name, ...) and
could not change a model. Usetx ls,tx get, andtx find(with--output-format json)
to read the same information. TheTOMIX_SCRIPT_FILE_NOT_FOUNDandTOMIX_SCRIPT_REQUIRED
codes are gone with it. - Breaking:
tx loadis replaced bytx summary, which is listed under Discover and reports
more: the source (path or workspace endpoint), on-disk format, culture, default storage mode,
and partition, calculation group, perspective, and culture counts alongside the old ones. - Breaking: the compatibility
-q <property>/-i <value>options ontx addandtx set
are removed. Use--set <property>=<value>(repeatable;<property>=-reads stdin) and, on
add,--expression/-efor the new object's value.-qnow means--quieton every command.
TheTOMIX_SET_INPUT_CONFLICT,TOMIX_ADD_INPUT_CONFLICT, andTOMIX_ADD_VALUE_REQUIREDcodes
are gone with them.
What's Changed
- feat(bpa): DAX-rewrite fixes for column and measure qualification by @bgarcevic in #326
- feat(bpa): author custom rules with bpa rules add/set/remove/init by @bgarcevic in #328
- feat(doctor): shareable report, current session, and honest update advice by @bgarcevic in #331
- refactor: source-generated JSON and a single-binary Native AOT preview by @bgarcevic in #329
- feat(bpa): author rules in the model's BestPracticeAnalyzer annotation by @bgarcevic in #332
- feat(get): compact property view with --all and property suggestions by @bgarcevic in #334
- feat!: remove tx script, replace tx load with tx summary, retire add/set -q/-i by @bgarcevic in #333
- chore(release): prepare 0.7.0 by @github-actions[bot] in #327
Full Changelog: v0.6.0...v0.7.0
v0.6.0
Fixed
tx validateno longer reports every column reference into a calculated table as missing
(DAX0002) when its TMDL declares no columns because the table was never evaluated. Columns
are inferred fromDATATABLE(...)andROW(...)expressions, so typos are still caught;
references into calculated tables whose columns cannot be inferred offline are not judged (#320).tx validatein CI logs: with--ci(or under Azure Pipelines), findings are no longer
hard-wrapped at 80 columns, so each one stays on its own line. In Azure Pipelines, a column
named like a log command ([Group],[Section],[Error], ...) no longer turns its line
into a collapsible section header that drops the##[error]styling and leaves stray8m
fragments in the table.tx validateno longer warns (DAX0003) about columns an expression defines for itself:
[@Name]when"@Name"is a new column's name inADDCOLUMNS,SELECTCOLUMNS,
SUMMARIZE,SUMMARIZECOLUMNS,GROUPBY,ROW, orDATATABLE, and[Value]from
GENERATESERIESor a{ ... }table constructor (not anIN { ... }list).tx validatenow checks where those columns are used: a column an expression builds is
accepted only where a row of its table is in context (insideFILTER,SUMX, and other
iterators over it, also through aVAR), and a use outside it warns withDAX0003"is built
by this expression but used outside the table that has it".
What's Changed
- fix(validate): infer columns of undeclared calculated tables by @bgarcevic in #320
- docs(changelog): move #320 entry to [Unreleased] and document the rule by @bgarcevic in #321
- fix(validate): readable CI logs and no warnings for query-scoped columns by @bgarcevic in #323
- fix(validate): scope-check columns an expression builds itself by @bgarcevic in #324
- chore(release): prepare 0.6.0 by @github-actions[bot] in #322
Full Changelog: v0.5.0...v0.6.0
v0.5.0
Added
tx bpa run --fix --dry-runpreviews fixes without changing the model. Each pending fix is
listed asWould fix:(orWould delete:with--allow-delete) with the property's value
before and after, followed by how many findings would remain. Nothing is applied, saved, or
staged, and the exit code still follows--fail-onfor the model as it is. JSON adds
dryRun,fixesPending,wouldRemain, and afixesarray with each fix's before and after
values; outside a dry run,fixeslists the fixes that were applied (#268).tx connect <workspace> --listlists the semantic models on a workspace or XMLA
endpoint without connecting (name, compatibility level, last update). It works
non-interactively and with--output-format json, so scripts and agents can
discover models on a workspace that hosts more than one.tx refreshreports refresh progress in detail: a live panel shows overall progress and each
in-progress table's step (querying, reading, compressing, hierarchies, calculated columns),
partition, rows, and running time, then the model-level steps (relationships, calculation
script, commit). It replaces the single status line, which on large models was cut off at the
terminal width and kept showing the same few tables. The summary adds aProcess
column, a row per partition for multi-partition tables, and a phase table; JSON gains
tables[].processMs,tables[].partitions, andphases.
Changed
- Opening a workspace that hosts several models without naming one now fails with
TOMIX_DATABASE_REQUIRED(exit 2) and a hint to runtx connect <workspace> --list,
instead ofTOMIX_CONNECT_FAILED/TOMIX_QUERY_FAILED(exit 1).
Removed
- Breaking:
tx query --planand theplansfield oftx query --output-format json. Power BI /
Fabric XMLA endpoints never deliver query-plan trace events, so the option could not return a plan.
Fixed
tx refreshreported only the last partition's rows and timings for tables with several
partitions, and on Power BI / Fabric could summarize before the trace arrived, reporting zeros
(typically with--output-format json).tx query --tracereturns server timings on Power BI / Fabric XMLA endpoints. The trace was
rejected for an unsupported column, and events that arrived were then silently discarded; timings
(andbenchmarkstorage-engine stats) came backnull. A missing timing now always comes with a
warning on stderr.
What's Changed
- ci: automate releases with verified previews and a release PR by @bgarcevic in #315
- feat(connect): list models on a remote workspace with --list by @bgarcevic in #316
- fix(query)!: restore Fabric trace timings, detail refresh progress, remove --plan by @bgarcevic in #318
- feat(bpa): --dry-run for --fix previews fixes without applying them by @bgarcevic in #319
- chore(release): prepare 0.5.0 by @github-actions[bot] in #317
New Contributors
- @github-actions[bot] made their first contribution in #317
Full Changelog: v0.4.3...v0.5.0