Changelog
All notable changes to this project should be documented in this file.
The format is based on Keep a Changelog, and this project follows versioned releases.
[Unreleased]
[3.0.2] - 2026-10-27
Fixed
- Portfolio contract instances now carry the core storage's
__storage_layout__. Instances previously fell back to MetaTables' default layout. ForPortfolioEventLedgerTSthat default names the secondary index after the four identity dimensions, which is 70 characters, and MetaTables refuses derived names over PostgreSQL's 63-character limit. Every event-ledger instance therefore failed registration, which stopped a downstream consumer's hosted migration Job before it migrated anything. Instances of the other five contracts declare no layout and are unchanged.
[3.0.1] - 2026-10-27
Removed
- The registry write allow-list of 3.0.0:
apps.v1.policyand the Main Sequence ConstantMARKETS_REGISTRY_WRITERS. Which applications may trigger registry writes is the platform's grant: an application reaches the Markets API only when its workflow grants it theMainSequenceMarketsbranch, and every caller the API admits may write.registry_writestill records the acting identity of every write. A deployment that created the constant can delete it.
[3.0.0] - 2026-10-26
Breaking release 3.0.0. It renames the DataNode vocabulary to the MetaTables
time-index terms: packages, updater and configuration classes, and UID fields
that now name the identity they hold. See
ADR 0048
and Upgrading To 3.0.
Every pre-3.0 name keeps working through 3.x with a DeprecationWarning.
Producers built from a moved class get a new update_hash once; signal,
portfolio and strategy identities do not change. Dependent packages declare
ms-markets>=3,<4.
Added
- Provider-owned Index values (ADR 0047, decision 4):
configured_index_values_storage(cadence=..., namespace=, storage_app=, base=)builds a provider's<storage_app>__index_values__t_<cadence>table in its own namespace; without them it is Markets' own table, unchanged. The Index dataset catalog discovers and reads both. - Moving existing history into provider instances (ADR 0047):
msm.storage_copies.copy_time_index_rowscopies the rows of some keys that a target table lacks from another table of the same contract, through theTimeIndexRowsCopyupdater, and verifies every key; a second pass fills only the gaps.TableSeriesMove,msm_portfolios.services.series_movesPortfolioSeriesMoveandSignalSeriesMovemove a series and roll it back, including the catalog and signal-binding calls in a fixed order, andrun_series_moves/msm series move|rollbackrun a provider's moves. A move refuses, before switching the provider, a signal without aSignalMetadatarow; a portfolio rollback keeps the binding of a signal that did not move with it (PortfolioDatasets.unregister(..., unbind_signal=False)); moves takekeys_per_readanddeadline_seconds;msm seriespassesrollback=to a callable that accepts it. - Remote reads and lifecycle calls providers need (ADR 0047):
filterandcounttake<field>__gte,__gt,__lteand__ltrange bounds (msm.repositories.crudrange_filters);AssetSnapshots.latestreturns each asset's latest snapshot by identifier, uid or ticker (msm.services.assets.asset_identifiers_by_ticker);PortfolioDatasets.register_signalbinds any signal's weights instance;FormulaIndex.activate_definitionandretire_definitionbackactivate()/retire();GET /portfolio/values/takesoffsetandMarketsClient.portfolio_valuespages past 5,000 rows.CurrencySpotandFuturegainupsert_manyandfilter;AccountHoldingsSnapshots.get_manyreturns several snapshots in one call (msm.services.get_account_holdings_snapshots_response);PortfolioDatasets.unregisterremoves a catalog row for a rollback, andunregister_signalclears one signal's instance binding. - Provider time series (ADR 0047):
msm.storage_instances.configured_time_index_instancebuilds a provider-owned instance of any Markets time-index storage, with its columns, foreign keys and grain index, in the provider's namespace and Alembic base.configured_interpolated_prices_storagetakesnamespace,storage_appandbase, andInterpolatedPricestakesstorage_namespace,storage_appandstorage_base, without changingupdate_hash.msm_portfolios.api.datasets.PortfolioDatasets.register/reconcile/getrun the portfolio dataset catalog services through the remote backend. - Set-based row operations on every table row class, under both backends:
upsert_many(payloads)(one bulk upsert on__upsert_keys__, each payload validated through<Row>Upsert),count(**filters), andfilter(...)withorder_by,offsetand<field>__in.msm.repositories.crud.search_modelgainsorder_by.AccountHoldingsSnapshots.publish/getandAssetSnapshots.publishpublish holdings and asset snapshots into Markets, so an application on the remote backend needs no grant on those tables. - Under the remote backend,
msm.start_engine(models=[...])no longer attaches a Markets table that is only a foreign-key target of another namespace's table; the provider's tables reference it by physical name, and the provider needs no grant onmainsequence.markets. Runtime-backend processes attach foreign-key targets as before. msm.clientand the remote row backend (ADR 0047, decision 2). Withuse_remote_backend(MarketsClient.from_environment().backend)orMSM_API_BACKEND=remote, every public class method of a Markets row class (Asset.upsert,Portfolio.get_by_uid,CurrencySpot.upsert,Index.get_formula...) runs through the Markets API instead of MetaTables, so an application needs no grant onmainsequence.markets. A provider's own row classes keep the runtime backend. The client discovers theapirelease of theMainSequenceMarketsrepository in the caller's Environment and authenticates with its release token;MARKETS_API_URLandMARKETS_API_TOKENselect a local API. New routesGET /rows/andPOST /rows/{resource}/{operation}/serve it; writes go through the registry write policy.MarketsClient.portfolio_valuesandportfolio_weightsread catalogued portfolio time series.- Registry write policy (ADR 0047, decision 3).
apps.v1.policyruns before everyregistry_writeservice: an application (workload identity) may create, update or delete registry rows only when the Main Sequence ConstantMARKETS_REGISTRY_WRITERSlists its User uid for that resource or for"*"; other applications get403. People, requester-bound calls, Organization admins and calls outside a request are unaffected. A missing constant allows no application, and an unreadable or malformed one returns503. The Markets workload needsreaderon the constant. Deployments where applications write registry rows today must create the constant before upgrading. - The portfolio engine can write every output to a provider's own instances
(ADR 0047).
PortfolioRebalanceStateTS,PortfolioCalendarEventsTSandPortfolioEventLedgerTSare storage contracts with the factoriesconfigured_portfolio_rebalance_state_storage,configured_portfolio_calendar_events_storageandconfigured_portfolio_event_ledger_storage.PortfoliosUpdatertakesweights_output_table=andrebalance_output_table=for thePortfolioWeightsandPortfolioRebalanceupdaters it builds, andPortfolioWeightstakesrebalance_output_table=. Output tables do not enterupdate_hash, so no existing identity changes. - ADR 0047 proposes the Markets API as the application boundary: provider-owned namespaces and sidecars, a contracts package with a remote row backend, and contract-plus- instances for portfolio and signal time series catalogued by Markets. Its migration path step 1 is implemented in this release as described below, except per-service ownership and Team scoping policy, which is still open; the packaging split (step 2) and the provider and consumer moves (steps 3 and 4) are not.
PortfoliosTS,PortfolioWeightsTSandSignalWeightsTSare storage contracts with instances (ADR 0047, decision 5).msm_portfolios.data_nodes.contract_instancesaddsconfigured_portfolios_storage,configured_portfolio_weights_storageandconfigured_signal_weights_storage, which build an instance under a caller-chosen MetaTables namespace, physical-name app segment and optional SQLAlchemy base, with the contract's columns, dtypes, time index, index names and foreign keys and a stable identifier<Contract>.<instance_key>. The core tables remain the Markets-owned instance.PortfolioDatasetAvailabilityTable(PortfolioDatasetAvailability) catalogs, per portfolio, the values, weights and signal instance uids and the reconciled population state of the values instance, mirroringIndexDatasetAvailability.SignalMetadataTable.meta_table_uidrecords the signal's instance. Alembic revision0021creates the table and the column; no existing table, column or row changes.msm_portfolios.services.portfolio_datasetsaddsregister_portfolio_datasets,reconcile_portfolio_dataset_availability,list_portfolio_dataset_statesandverify_contract_instance. Registration verifies each declared table against the contract; reconciliation aggregates each instance once for all of its portfolios and records unreadable instances asunavailable.apps.v1.identityaddsacting_identity(), the one place the Markets API decides whom a request acts for:User.get_requester()on a requester-bound call,User.get_logged_user()otherwise, never both, andNoneoutside a request.registry_writewraps every API service that creates, updates or deletes a registry row (accounts, asset categories, assets, calendars, indexes, portfolio groups, portfolio signals, portfolios, pricing curves and pricing market data) and records the acting identity with the resource, action and row uid on theapps.v1.identitylogger after a successful write. The Index routes derive their actor from the acting identity, so a requester-bound call acts for the requester.- Markets API routes the ADR 0047 boundary needs:
POST /api/v1/account/andPATCH /api/v1/account/{uid}/(account create and update overmsm.api.accounts);POST /api/v1/index/{uid}/formulas/,.../{definition_uid}/activate/,.../{definition_uid}/retire/,.../formulas/preview/and.../{definition_uid}/preview/(formula save, activate, retire and preview overFormulaIndex, previews ascore.tabular_frame@v1);GET .../by-uids/?uid__in=batch lookups for assets, accounts, portfolios and indexes (at most 500 uids, request order, unknown uids omitted, no paging or discovery);GET /api/v1/portfolio/values/andGET /api/v1/portfolio/weights/multi-portfolio frames grouped by catalogued table; andPOST /api/v1/portfolio/{uid}/datasets/,GET /api/v1/portfolio/{uid}/datasets/andPOST /api/v1/portfolio/datasets/reconcile/for the portfolio dataset catalog. All are registered in the Command Center adapter contract; the mutating ones record the acting identity. The by-uid lookups acceptinclude=<sidecar MetaTable uid>and attach provider sidecar rows underincludes, resolving the sidecar's foreign key to the coreuidfrom the MetaTables catalog and reading each sidecar once (ADR 0047includehydration; the Markets workload needsdata_vieweron the sidecar). - A design note for the contracts package split and
msm.client(ADR 0047, decision 2) underdocs/planning/implementation_tasks/; the README now describesmsm.clientas planned rather than shipped. - The
markets-apiresource in.mainsequence/workflows/ms-markets-api.yamldeclaresacts_for_requester: true, so the platform signs the person an application works for into the caller assertion and the API acts for that requester (ADR 0047, decision 3). Caller-bound calls are unchanged. The declaration takes effect only when an Organization admin pushes it; a push by anyone else makes themarkets-apiresource fail before it deploys. tests/identity/test_pinned_identities.pypins the identities that a rename or a module move would rotate: the physical table name and MetaTable identifier of every library-owned model, themodule:qualnameof every shippedTimeIndexTableUpdaterandTimeIndexTableUpdateConfigsubclass (MetaTables hashes both into each producer'supdate_hash), and thesignal_uidand portfolio configuration hash of fixed library and application signal configurations. Changing a pinned value is a deliberate identity rotation and belongs in this changelog.- ADR 0048 records the rename of the DataNode vocabulary to the MetaTables time-index terms: package and class names, UID columns named after the identity they hold, a 3.x deprecation window, and expand-then-contract column migrations across 3.0.0, 3.1.0, 4.0.0 and 4.1.0.
msm.identitykeeps the identities ms-markets derives stable when an updater or configuration class moves.compute_signal_uid,compute_portfolio_configuration_hashand the newmsm_portfolios.configuration.compute_strategy_revision(which the portfolio engine now uses for ledger events) map moved class paths and nested updater hashes back to their pre-rename values before hashing. No class has moved yet, so every identity is unchanged; the pinned identity tests now also cover real updaters built offline, nested updater hashes, strategy revisions, factory-built storage tables and a simulated class move.- Alembic revision
0022addsholdings_storage_table_uid,source_storage_table_uid,portfolio_weights_table_update_uid,signal_weights_table_update_uid,portfolio_table_update_uidand an indexedstorage_table_uidnext to the pre-3.0*_data_node_uidcolumns and copies their values. No row or pre-3.0 column changes. ms-markets 3.x writes both columns on every CRUD and repository write path (msm.repositories.crud.mirror_renamed_columns, driven by each model's__renamed_columns__) and reads the pre-3.0 columns until every writer runs 3.x (ADR 0048). msm rename-preflighthelps host projects move to the 3.0 names.scanlists pre-3.0 import paths, class names and UID field names with their replacements, includinggetattr(..., "<pre-3.0 field>", default)calls that 4.0 would turn into silent defaults, and exits 1 while any remain.rotation module:callablereports each updater's new and pre-3.0update_hash.account-uidsclassifies the stored account and holdings-set UIDs as storage tables or table updates. The new Upgrading To 3.0 page describes the upgrade order.
Changed
- Renamed packages and classes (ADR 0048).
msm.data_nodes,msm_portfolios.data_nodesandmsm_pricing.data_nodesare nowmsm.time_index,msm_portfolios.time_indexandmsm_pricing.time_index, andmsm_portfolios.contrib.prices.data_nodesismsm_portfolios.contrib.prices.updaters.*DataNodeupdaters are*Updater,*DataNodeConfigurationclasses are*UpdaterConfiguration,TargetPositionsDataNodeConfigurationisTargetPositionsConfiguration, andDiscountCurvesNodeandFixingRatesNodeareDiscountCurvesUpdaterandFixingRatesUpdater. Storage classes, physical table names and MetaTable identifiers are unchanged. The asset-indexed skill folder is nowassets/asset_indexed_updaters; re-runmsm copy-msm-skillsto replace the old folder. - Identity rotation. MetaTables hashes each updater's and each
configuration class's import path into
update_hash. Every producer whose class or configuration class moved, or that nests such a producer, gets a newTimeIndexTableUpdateon its first run under 3.0.0. The old record keeps its run history, and the producer continues from its output table's last observation.signal_uid, portfolio configuration hashes and rebalance strategy revisions do not change;msm.identitymaps the moved paths back. - Renamed UID fields (ADR 0048). Row APIs, payloads, repositories, services
and HTTP responses use
holdings_storage_table_uid(Account),source_storage_table_uid(AccountHoldingsSet),portfolio_weights_table_update_uid,signal_weights_table_update_uidandportfolio_table_update_uid(Portfolio), andstorage_table_uid(PricingMarketDataSetBindingand the curve and resolve responses).PricingMarketDataConfiguration.data_node_uidsisstorage_table_uids,PricingMarketDataSetBinding.resolve_data_node_uidisresolve_storage_table_uid,direct_data_node_uid_forisdirect_storage_table_uid_for, and the virtual-fund allocation methods takeupdater=instead ofdata_node=. Rows read the pre-3.0 column, which 2.x writers still update. Portfolio detail fields use the new keys and the labels "Portfolio Weights Table Update", "Signal Weights Table Update" and "Portfolio Values Table Update"; the Command Center binding column isstorage_table_uid. Missing-curve messages call the bound UID a storage table instead of a TimeIndexTableUpdater. portfolio_values,latest_portfolio_weightsand the newsignal_weightsread inmsm_portfolios.services.portfolio_readsresolve each portfolio's table from the catalog and read it by uid throughTimeIndexTableRef, filtered byportfolio_identifierorsignal_uid. Portfolios without a catalog row read the core tables as before. A request for several portfolios groups them by table uid, reads each table once and returns one ordered list.latest_portfolio_weightsgainsorder, and the reads accept adataset_readerfor tests. The portfolio values, weights and signal-weight API routes use these reads. Theapps/v1runtimes attachPortfolioDatasetAvailability.- ms-markets requires
mainsequence-metatable>=0.1.57,<0.2(was>=0.1.51). 0.1.57 is the first MetaTables release that computes theupdate_hashof an updater whose configuration holds adatetime.dateordatetime.time.
Deprecated
- The pre-3.0 import paths
msm.data_nodes,msm_portfolios.data_nodes,msm_pricing.data_nodesandmsm_portfolios.contrib.prices.data_nodes, with every submodule, are aliases of the renamed modules through 3.x. They re-export the same objects and raise aDeprecationWarningat the importing line. The pre-3.0 class names, such asAssetIndexedDataNode,PortfoliosDataNodeandDiscountCurvesNode, resolve from those paths and frommsm_portfolioswith a warning. Stored configurations that name the old paths still rebuild. ms-markets 4.0 removes the aliases. - The pre-3.0 UID field names (
holdings_data_node_uid,source_data_node_uid,portfolio_weights_data_node_uid,signal_weights_data_node_uid,portfolio_data_node_uidanddata_node_uid) stay readable on rows and in every HTTP response, where OpenAPI marks them deprecated, and requests, payloads, row writes and repository builders accept them with aDeprecationWarning.data_node_uids,resolve_data_node_uid,direct_data_node_uid_for,data_node=andmsm.settings.markets_data_node_identifierare deprecated aliases. ms-markets 4.0 removes them.
Fixed
-
Every hosted rollout since 2026-10-21 stopped at the
migrate-marketsJob withNo package metadata was found for ms-markets. Main Sequence images no longer install the repository itself (platform ADR-080); Jobs and the Markets API import it from/workspace.msm, the API and the CLI now read the version throughmsm.distribution.package_version(), which falls back to the checkout'spyproject.tomlwhen the distribution is not installed. -
requirements.txt, the only dependency input of a Main Sequence image, still pinnedmainsequence-metatable==0.1.51after the floor moved to 0.1.57, so the image lackedmetatables.envelope_contract. It is regenerated withmainsequence code-repository sync, and a test now fails when its pins differ fromuv.lock. -
A storage instance built on a provider's declarative base copied each referenced Markets table whole, with that table's own foreign keys to tables that were not copied, so the provider's
metadata.sorted_tablesand Alembic autogenerate failed withNoReferencedTableError. The provider's metadata now holds only the referenced key columns of each Markets table (msm.storage_instances.markets_reference_table). -
Building a storage instance on a provider's declarative base raised
TypeError: Boolean value of this clause is not definedonce the base already held a copied foreign-key target (any table with two foreign keys to one Markets table, such as trades or the event ledger, or a second instance on the same base); the copied target is now reused.msm.start_engineaccepts such instances: they are notMarketsBasesubclasses but carry the Markets mixins. -
The portfolio guide's provider example passed
namespace=toPortfoliosUpdater, which is the hash namespace and rotatesupdate_hash. -
Under the remote backend,
PersistedCalendarSchedule.schedule(calendar-relative rebalancing) andFormulaIndex.activate()/retire()ran compiled SQL in the calling process and failed; they now run through dispatched row methods. Index.upsert_manynow appliesIndex.upsert'scalculation_methodguard to every existing index.-
A holdings snapshot read scanned at most 500 holdings rows in no order, so for a larger account the latest (or earliest) snapshot could be missed. The scan is ordered by time, and a dated read filters on that date.
-
UID column labels and descriptions name the identity each column holds. The three
PortfolioTable.*_data_node_uidcolumns are labelled asTimeIndexTableUpdateuids, which is what the portfolio updaters write.PricingMarketDataSetBindingTable.data_node_uidis labelled as the storage table uid it is resolved through.AccountTable.holdings_data_node_uidandAccountHoldingsSetTable.source_data_node_uiddescribeTimeIndexMetaTableuids, as their originalDataNodeStoragedescriptions did, instead of being labelled as updater uids. The Command Center market-data binding columns read "Storage table UID", and the API settings namespace assumption names time-index table updaters instead of DataNodes. Column names, API fields and MetaTable contract hashes are unchanged; the catalog refreshes the labels on the next migration finalization. docs/concepts.mddescribes timestamped data in MetaTables terms: aPlatformTimeIndexMetaTablestorage class written by aTimeIndexTableUpdaterproducer, instead of a single DataNode storage contract.includeon the by-uid lookups no longer returns application-encrypted sidecar columns. Markets skips every column the MetaTables catalog marks withencryption(MetaTables ADR 0025) and drops any value that is anmt1.encryption envelope, so a provider can grant the Markets workloaddata_vieweron a sidecar that holds credentials without its ciphertext reaching Markets responses. A sidecar whose join column is encrypted is refused.from <pre-3.0 module path> import <name>no longer recurses forever. The import system probes__path__on every from-import, and the deprecated alias modules treated that dunder as a submodule to import, which probed__path__again. Aliases now answer dunder lookups withAttributeErrorand try submodule imports only for package aliases. Every module alias is tested with a from-import.- Portfolio, portfolio-weights, signal and signal-weights deletes respect the
ADR 0047 catalog. They used to touch only the core tables, so a portfolio
catalogued in another application's contract instance reported zero rows
deleted and kept its data.
DELETE /portfolio/{uid}/weights/andDELETE /portfolio-signal/{uid}/weights/now return 409 and delete nothing when the weights live in a table another application owns (PortfolioDatasetOwnershipError,SignalDatasetOwnershipError). Portfolio and signal deletes, including bulk and cascade, still delete the Markets rows and any core rows, and list each table they left in place in a newretained_datasetsfield. The bulk-delete preflight warns about those tables. A catalog row that names the core table counts as core. compute_portfolio_configuration_hashandcompute_signal_uidno longer raiseTypeErrorwhen a configuration holds adatetime.dateordatetime.time, such as the execution window ofTimeWeighted,VolumeParticipationandTrailingAverageDailyVolumeParticipation. The canonical signal, portfolio and rebalance strategy payloads carry these values as ISO strings. Configurations that hashed before keep their identities, and rebalance strategy revisions do not change. With MetaTables 0.1.57, which ms-markets now requires,PortfolioWeightsandPortfoliosUpdateralso compute theirupdate_hashfor a portfolio that uses one of these strategies, instead of raising the sameTypeError.
[2.2.12] - 2026-10-22
- Require certifi 2026.10.19 or newer so downstream installs receive the corrected CA bundle; refresh the matching lock/export pins.
- Use Python 3.13.17 and patched pip/uv bootstrapping in CI. This release changes dependency security requirements without changing application APIs.
[2.2.11] - 2026-10-21
Changed
- Requires
mainsequence>=9.0.29,<10andmainsequence-metatable>=0.1.51,<0.2; the lock and exportedrequirements.txtselectmainsequence9.0.30,mainsequence-metatable0.1.51 and, through them,mcp2.3.0. SDK 9.0.24 and earlier refuse the platform's identity-only caller assertions, so the Markets API, locked at 9.0.19, answered401to every signed request; SDK 9.0.25 and 9.0.26 raise when code reads the request identity'steam_uids; and MetaTables clients before 0.1.51 fail on SDK 9.0.30. This release adds no Alembic revision. - The deployment workflow uses workflow API
3.0.0, the only version the platform accepts:markets-apiandmigrate-marketsdeclarepolicy: readeron the MetaTables branch, the conversion of their formerlevel: view. - MetaTables access follows its namespace and table roles (MetaTables ADR 0024). On
mainsequence.marketsthemigrate-marketsJob holdseditor, themarkets-apireleasedata_writer, and a person or a people-only Teamowner; the namespace's owners grant these in each Environment. The release, migration and FastAPI guides and the packagedmetatable_migrationsskill describe them, with the roles consuming projects need:editorfor migration Jobs that register tables inmainsequence.markets, tableeditoron their outputs plusdata_viewerfor updater producers,data_writerfor row writers anddata_viewerfor readers. IndexActor.team_uidsis deprecated and empty for HTTP callers, because caller assertions name no Teams. The Index actor never reads the request identity'steam_uids; an SDKUserstill contributes itsorganization_teams. No Index operation authorizes by Team.- Canonical Index dataset discovery no longer reports
can_edit=Trueto the user who registered the table, because registering grants no MetaTables role by itself.can_editisNone; the platform checks edit access when a change runs. get_openfigi_api_key()raisesOpenFigiConfigurationErrornamingvalue_readeronOPEN_FIGI_API_KEYwhen the caller may not read the Secret's value. Its missing-Secret message also says that a Secret is hidden from a caller without a policy on it. A deployment that calls OpenFIGI declaressecrets: [{name: OPEN_FIGI_API_KEY, policy: value_reader}].- Test fixtures sign identity-only caller assertions, and a test checks that an
assertion listing
team_uids, for the caller or for a requester, is refused. - Refreshed the copied Main Sequence SDK skills to 9.0.30 and the MetaTables skills to
0.1.51 (0.1.35 dropped the retired
metatables-upgrade-legacy-appskill), and removed the retired managed block fromAGENTS.md:mainsequence code-repository updateno longer exists.
Removed
scripts/bootstrap_metatables_access.pyand its tests. It called Team bulk-member and MetaTables Reader/Writer routes that no longer exist, and roles replace its Team Writer model.mainsequence.marketsexists in the development and Production Environments, and its owner grants the roles above.
[2.2.10] - 2026-10-11
Fixed
- Retry read-only API startup attachment after explicit temporary gateway authentication
or MetaTables wake failures within one 300-second budget. Production previously exited
on the first transient
503; invalid credentials, permissions, schema errors, and persistent failures still prevent startup. Normal request behavior is unchanged.
[2.2.9] - 2026-10-11
Fixed
- Give FastAPI startup an explicit 300-second MetaTables discovery scope for canonical and pricing runtime attachment. A waking shared API previously exhausted the ordinary 30-second budget and failed development rollout. Startup still propagates attachment errors; normal request budgets are unchanged.
Changed
- Document the shared MetaTables API 0.1.34 dependency for finalizing the
populated legacy TimescaleDB schema after the committed
0020upgrade. Its ownership-before-conversion repair preserves rows without adding internal schema grants. Retry through the hosted migration Job; client requirements, applied Alembic revisions, and development tables remain unchanged.
[2.2.8] - 2026-10-11
Fixed
- Give the hosted migration Job an explicit 300-second MetaTables discovery
scope, so waking APIs receive the documented migration wait budget instead
of the ordinary 30 seconds. Schema and catalog errors still fail the Job;
the data-preserving
0017bridge and applied revisions stay unchanged.
[2.2.7] - 2026-10-11
Fixed
- Restore a forward upgrade for populated PostgreSQL databases at the retired
0017head, which blocked the Production API rollout. A compatibility anchor and merge revision0020join that history with development's0018/0019without changing those applied revisions or replacing application tables. - Validate all 62 application table column contracts before reconciliation; refuse overlong identifiers, bound only ten known legacy string columns, and verify locked tables' row counts and checksums remain unchanged. Extra tables and columns are preserved. Already-bounded development needs no alterations.
- Add original-history PostgreSQL data-preservation and failure regressions, fresh/development upgrade checks, and matching migration guide, release instructions, ADR 0046, tutorial, and print-only lifecycle example.
[2.2.6] - 2026-10-10
Added
scripts/bootstrap_metatables_access.pygives the deployment's workload Users Writer on themainsequence.marketsMetaTables namespace in one Environment, for an Organization admin to run once from a checkout ofdevelopmentormain. It creates the Teamms-markets-<environment>from the checkout's Environment name, adds the migration Job's and FastAPI release's workload Users from the deployment workflow, creates the namespace if it is missing and grants the Team Writer on it. Every other grant is kept, and--dry-runonly reports. Without this grant the migration Job could not register tables. Indevelopmentit got422 MetaTable is not editableonmsm.alembic_version, which a previous runtime identity had registered. See MetaTables#43 and "MetaTables access in each Environment" indocs/releasing.md.
Changed
- Requires
mainsequence-metatable>=0.1.33,<0.2; the lock and runtime export select 0.1.33, while Main Sequence remains 9.0.19. The shared migration runner batches table inventories and inspections and waits up to 300 seconds for a waking API, addressing the 30-second discovery timeout in the failed Markets deployment (MetaTables#55). Server-side batching, unchanged-contract write avoidance, and startup improvements also require deployment of the updated shared MetaTables API. - The upgraded migration runner carries changed, non-empty authored table and column metadata through finalization at an unchanged Alembic revision. Empty values preserve existing catalog metadata and equal-valued reruns avoid catalog writes. The matching API update is required for this payload; it also fixes SQLite schema reflection during multi-batch downgrade finalization (MetaTables#59).
- The migration Job exposes the shared runner's INFO phase timings, always reconciles the catalog even at head, and propagates failures to block rollout. Provider identity, version-table binding, and applied revisions are unchanged.
- Refreshed the MetaTables-owned skills and guide snapshots to 0.1.33; aligned migration documentation, release guidance, tutorial, and print-only example.
- Requires
mainsequence-metatable>=0.1.29,<0.2; the lock and exportedrequirements.txtselect 0.1.29. Changes in MetaTables 0.1.29 (MetaTables#52): - Hosted migrations no longer create application tables in the
metatablescatalog schema. The migration connection pinssearch_path=public, the client checks it, and the PostgreSQL version table is always schema-qualified (MetaTables#50). The first ms-markets migration indevelopment, on 2026-10-03, had created all its tables inmetatables, so every later migration found its version table at head, ran no DDL and failed finalization. MetaTables removed those tables, so the next deployment creates them inpublic. - Before issuing a migration connection, the API refuses misplaced provider
tables with
provider_tables_misplaced. - Finalization deletes a catalog binding only for a table the client names as removed. It no longer drops the bindings of current tables it can't find.
- The vendored MetaTables agent skills are refreshed to 0.1.29.
- Requires
mainsequence-metatable>=0.1.28,<0.2; the lock and exportedrequirements.txtselect 0.1.28. Changes in MetaTables 0.1.28 (MetaTables#49): - The client finalizes at most 10 tables per request, the Alembic version table first. A rerun of the migration Job finalizes whatever an interrupted run left. Finalizing all 62 ms-markets tables in one request ran past the hosted request limit, so the migration could never finish (MetaTables#46).
- The hosted API reuses connections and serves concurrent requests on more resources, so a long request no longer leaves it refusing connections (MetaTables#45).
- A busy API answers
503database_connections_busywithRetry-After; nothing ran, and the call can be retried. - The vendored MetaTables agent skills are refreshed to 0.1.28.
- Requires
mainsequence-metatable>=0.1.27,<0.2; the lock and exportedrequirements.txtselect 0.1.27. Changes in MetaTables 0.1.27 (MetaTables#44): - One platform Team per Environment owns an application's tables, with the
application's workload Users as members. This is what
scripts/bootstrap_metatables_access.pysets up. - A table registered in a namespace the caller already writes gets no grant of its own.
- A refused registration answers
403table_not_editableornamespace_not_writable, with the caller's User UID. - The vendored MetaTables agent skills are refreshed to 0.1.27. The
metatables-migrationsskill makes the per-Environment Team a deployment step. - Requires
mainsequence>=9.0.19,<10andmainsequence-metatable>=0.1.26,<0.2; the lock and exportedrequirements.txtselectmainsequence9.0.19 andmainsequence-metatable0.1.26. MetaTables 0.1.24 and later requiremainsequence[mcp]>=9.0.19and always installfastembed, soonnxruntime,tokenizers,huggingface-hubandmcpare new runtime dependencies (about 100 MB installed). The API does not import them at startup. No ms-markets code uses an API that changed in this range. - The local MetaTables API is now one per laptop. After upgrading, restart
metatables serve --localand apply the local system migration0011_table_search(metatables --local runtime upgrade); projects on MetaTables 0.1.21 or earlier then fail against the shared local file. - Every request to the Markets API is authenticated before its handler (see
Fixed). A local request must send the signed-in user's
Authorization: Bearertoken, which is checked againstMAINSEQUENCE_ENDPOINT; without one it receives401. - Refreshed the Main Sequence SDK agent skills and the managed
AGENTS.mdblock to 9.0.19, and the MetaTables agent skills to 0.1.26. The 0.1.18 MetaTables skills said registered foreign keys must useRESTRICTorNO ACTION; 0.1.26 allows any referential action, including the cascades ms-markets declares.
Fixed
- Repair the portfolio event ledger's TimescaleDB-incompatible non-time unique
constraint through forward migration
0019, preserving applied0018, all existing rows, and full-grain uniqueness. Canonical publication, restart, and projections reject duplicate economic record identities across timestamps and event revisions split across times. Exact retries remain idempotent. - Align ADR 0042, accounting and migration documentation, the portfolio tutorial, and the offline dividend/FX example with the storage and validation boundary.
- The Markets API installs the SDK request identity with
install_request_identity(app)increate_app(). The platform launcher refuses to serve an application that does not install it, and SDK releases before 9.0.18 reject the platform's current caller assertions. Handlers read the verified caller fromrequest.state.user, which the platform never injected, so the Index routes treated every hosted request as anonymous. - The Index actor takes its Teams from the request identity's
team_uids. It readorganization_teams, which a request identity does not have, so an HTTP caller's Teams were always empty. - The
markets-apirelease and themigrate-marketsJob declareaccess.branchesview on the MetaTables repository in the deployment workflow, and the platform grants it to their workload Users on every push. They run as their own workload Users, and MetaTables API discovery failed without that access: "No visible FastAPI deployment named 'metatables'", then "Cannot verify the Environment of every visible API deployment". msm_portfolios.utils.get_portfolios_logger()returns the logger bound withsub_application="portfolios". It discarded the result of.bind()and returned the unbound SDK logger, somsm_portfolios.utils.loggerand themsm_portfolios.configurationlogger never carried the binding.examples/msm_portfolios/portfolio_equal_weights_prepare_schema.pyruns the dynamic Alembic revision and upgrade through themetatables migrationsCLI. It invokedpython -m mainsequence migrations ..., which the SDK no longer provides, so schema preparation failed unless--check-onlywas set.- Removed a stray module-level developer note from
msm_portfolios/configuration.pythat referenced the retired SDKdata_publishingskill by a local absolute path.
[2.2.5] - 2026-10-04
Fixed
TabularFrameResponseand its field, source, time-series and table-visual models omit unset optional fields instead of serializing them asnull, which thecore.tabular_frame@v1schema rejects. A plain dump ofbuild_tabular_frame(...)failed the schema onerror,meta,sourceand the fieldlabel,provenance,derivedFromandwarnings; only routes declared withresponse_model_exclude_none=True, as every ms-markets frame route is, returned a valid frame.nullcell values inrowsare kept. A test fails if any optional field of the bulk-action, resource-collection or tabular-frame contract models serializes asnull, other thanBulkDeletePreflightResponse.impact, and the Command Center connection contract is validated against the Adapter from API discovery schema.
[2.2.4] - 2026-10-04
Fixed
BulkActionDefinitionomitstone,confirmationandpreflight_endpoint, andBulkActionPreflightResponseomitsdetail,matched_count,blockersandwarnings, when they are unset, instead of serializing them asnull. The Command Center SDK accepts these fields only when they are absent or valid, so a discovery route that advertised an action without atoneorconfirmationfailed with "Bulk-action discovery returned an invalid action definition.", and a preflight that left any of those fields unset failed to parse (#22). The ms-markets bulk-delete routes set every field and were not affected. A contract test dumps the resource-discovery and preflight models with only their required fields and checks that the output has nonullvalues and validates against the pinned SDK schemas.
[2.2.3] - 2026-10-03
Added
- The portfolio, portfolio-group and asset-category bulk-delete preflights
report what the delete reaches through foreign keys. They return the
MetaTables
delete_rowsimpact asimpactand describe each cascade,SET NULLorSET DEFAULTaction inwarnings. MetaTables' blockers (the caller cannot write the table, the table does not accept writes, or its DataSource is read-only) are added toblockersand also stop the bulk delete with409; cascades never block. If MetaTables cannot compute the impact, a warning says so and the delete is not blocked.BulkDeletePreflightResponseand theTableImpactmodels are exported frommsm.api.http, anddelete_rows_impactfrommsm.services.
Changed
- Requires
mainsequence-metatable>=0.1.18,<0.2; the lock and exportedrequirements.txtselectmainsequence-metatable0.1.18. MetaTables 0.1.18 removes the cascade write narrowing released in 0.1.17: write on a table depends only on its own grants, so a foreign key on a referencing table no longer locks the referenced table's Writers out. Its impact pre-flight reports cascades as information, never as blockers. - Refreshed the MetaTables agent skills to 0.1.18.
[2.2.2] - 2026-10-03
Changed
- Requires
mainsequence-metatable>=0.1.17,<0.2; the lock and exportedrequirements.txtselectmainsequence-metatable0.1.17. Earlier releases refuse to finalize tables with cascading foreign keys (cascading_foreign_key_unsupported), so the ms-markets provider could not finishmigrations upgrade. MetaTables 0.1.17 allows them: writing a table requires write access on every table its cascades modify. The ms-markets cascades are unchanged. - Refreshed the MetaTables agent skills to 0.1.17. They document explicit
__storage_layout__names, cascading foreign keys and theget_impactpre-flight.
Fixed
PortfolioEventLedgerTSdeclares an explicit__storage_layout__whose lookup index is namedportfolio_event_ledger_identity. The default layout derived a 70-character name from its four identity dimensions, which MetaTables rejects (it never shortens derived names), so the ms-markets migration provider could not be applied in any new environment (#19). A test runs the MetaTables layout check on every provider time-index model.
[2.2.1] - 2026-10-03
Changed
- The VS Code launch configurations and tasks that check, apply and downgrade
migrations pass
--local, so they act on the local runtime instead of whichever MetaTables API the SDK environment resolves, and their names say so.
Documentation
- The FastAPI deployment docs describe workflow API 2.3.0 and its
image→migrate→deploy_apigraph, and say that publishing is a plaingit push. Since Main Sequence SDK 9.0.5,mainsequence code-repository synconly refreshesuv.lock, the environment andrequirements.txt; it no longer bumps, tags, commits or pushes. - Every developer migration command targets the local runtime
(
metatables --local), including the ADR 0045 reset path. Hosted environments are migrated only by the deployment workflow's Job. - Downstream projects declare their own migration provider and version table.
The MetaTable migration, portfolio accounting and asset-indexed storage
guides, the pricing tutorial and the bootstrap, index and
metatable_migrationsskills no longer suggest extending the ms-markets revision graph or applyingmsm_migrations:migrationoutside the ms-markets deployment. - MetaTable registration no longer describes the removed catalog projection
hook, and the
metatable_migrationsskill's project provider example uses the locationsmetatables migrations scaffold --modulederives. - Refreshed the MetaTables agent skills to 0.1.14 and the managed
AGENTS.mdsection from SDK 9.0.5; the SDK skill bundle is unchanged.
[2.2.0] - 2026-10-03
Removed
- Breaking: the
msm_command_centerpackage is removed. Import thecore.tabular_frame@v1models and helpers (TabularFrameResponse,TabularFrameMetaResponse,TabularFrameFieldResponse,TabularFrameSourceResponse,build_tabular_frame,build_tabular_field,CORE_TABULAR_FRAME_CONTRACT) frommsm.api.http.infer_tabular_field_typeis removed. - Breaking:
build_asset_monitor_frameandbuild_asset_monitor_workspace_documentare removed.getAssetMonitorFramebuilds its frame insideapps/v1and its response is unchanged; workspace documents are not built by this library. - Breaking: fixed income pricing support no longer returns
response_mappings, and the cashflow response schemas no longer carryx-response-mappings. Command Center SDK 0.1.13 retired response mappings; bind thecashflows/frame/andnet-cashflows/frame/routes instead. - Breaking:
getAssetMonitorFramereturns only theuid,unique_identifier, andasset_typecolumns, and itsmeta.marketAssetno longer names atickerField. The removedticker,name,figi,composite_figi,exchange_code,security_type,security_market_sector, andcurrencycolumns were always null: the asset list does not load them. - The
apps/v1re-export modules are removed:apps.v1.schemas.command_center,apps.v1.schemas.resource_contracts,apps.v1.schemas.bulk_actions,apps.v1.services.resource_collections,apps.v1.services.bulk_actions, and theErrorResponsere-export inapps.v1.schemas.common. Import frommsm.api.http. - The Command Center Asset Monitor skills are removed.
Changed
- Adapter from API discovery takes an operation's
responseContractonly from itsx-ui-contractdeclaration; it no longer inferscore.tabular_frame@v1from a response model namedTabularFrameResponse. Every frame route already declares it, so the advertised contracts are unchanged. - Requires
mainsequence-metatable>=0.1.14,<0.2; the lock and exportedrequirements.txtselectmainsequence-metatable0.1.14. MetaTables 0.1.13 and 0.1.14 change only how a failed runtime database bootstrap names its cause.
[2.1.2] - 2026-10-03
Changed
- Releases follow the MetaTables branch model. Every push to
developmentpublishes anX.Y.Z.devNbuild to PyPI.mainis protected, and each merged pull request fromdevelopmentpublishes the declaredX.Y.Z, creates thevX.Y.Ztag and GitHub release, deploys the documentation and returns the next patch version todevelopment. Pushing av*tag no longer publishes. - Pull requests and both publishing workflows run
Package and static checks: the lockfile, Ruff, the strict documentation build, the full test suite, and a distribution check that the wheel and sdist match the current sources. - The
devextra addsbuild,packagingandtwine>=7. twine 6 rejects theMetadata-Version: 2.5that hatchling writes.
Documentation
- Added the Releasing guide.
[2.1.1] - 2026-10-03
Changed
- Renamed the deployment workflow file from
.mainsequence/workflows/fastapi.yamlto.mainsequence/workflows/ms-markets-api.yaml. Itsname, resources and execution graph are unchanged.
Fixed
api_http_errormaps the SDKConflictErrorto a non-retryable409conflictresponse with a fixed message, instead of a retryable503dependency_unavailable. Fixes #13.
Documentation
- Aligned the migration docs and examples with the MetaTables 0.1.12 guidance:
manual
upgrade/downgradecommands target the local runtime (--local), hosted schema changes come from themigrate-marketsdeployment Job, raw PostgreSQL SQL in a revision must branch on the dialect, and the 2.1.00018_initial_schemasquash replaces the old revision history. The documented client requirement ismainsequence-metatable>=0.1.12,<0.2. Refreshed the MetaTables agent skills to 0.1.12. - Withdrew the 2.1.0 instruction that applications reading ms-markets tables
apply
msm_migrations:migrationin their own migration Job. The migration docs and the shippedmetatable_migrationsskill now state that only the ms-markets deployment'smigrate-marketsJob migrates the ms-markets schema; other applications apply only their own providers.
[2.1.0] - 2026-10-03
Changed
- Breaking: the migration history is one revision,
0018_initial_schema, generated from the models;0001–0017are removed, which withdraws the 2.0.2 promise that they stay unchanged. No old ID is reused, so a database at any of them fails with an unknown-revision error instead of passing as head. Downgrade it tobasewith 2.0.x installed, then apply 2.1.0 from empty. The provider key,MarketsAlembicVersionand its table are unchanged. The history now builds on the MetaTables local SQLite runtime as well as PostgreSQL (ADR 0045, #12, #15). - Breaking: the
cliandcommand_centerpackages are renamedmsm_cliandmsm_command_center, and bundled skills ship insidemsm_cli/_skills. The wheel installs onlymsm*packages; themsmconsole script is unchanged (#14). - Requires
mainsequence>=9.0.5,<10andmainsequence-metatable>=0.1.12,<0.2; the lock and exportedrequirements.txtselectmainsequence9.0.5 andmainsequence-metatable0.1.12. - The Markets API deployment workflow (
.mainsequence/workflows/fastapi.yaml) moves to workflow API 2.3.0 and runs a migration Job,jobs/migrate_markets.py, from the candidate image before the API deploys. The Job appliesmsm_migrations:migrationwithmetatables.upgrade_application(...); a failed migration blocks the rollout. - Migration docs and the shipped
metatable_migrationsskill scope manualmetatables migrations upgradeto the local runtime (--local). Hosted environments are migrated only by the deployment workflow's Job, and applications that deploy code reading ms-markets tables applymsm_migrations:migrationin their own migration Job first.
[2.0.2] - 2026-10-02
Changed
- Breaking: the Alembic migration provider moved from the top-level
migrationspackage tomsm_migrations, and the wheel no longer installs a top-levelmigrationspackage. Usemetatables migrations ... --provider msm_migrations:migration;msm.migrations:migrationremains a compatibility alias. The provider keymsm:<namespace>,MarketsAlembicVersion, and revisions0001–0017are unchanged, so existing databases continue from their current revision. See ADR 0044 and #14. - The provider now sets
version_location_prefix="msm_migrations:versions"instead of relying on the client defaultmigrations:versions.
Removed
- The unreachable
versions/defaultrevision directory and the redundantscript.py.makowheel force-include.
[2.0.0] - 2026-10-01
Breaking release for Main Sequence SDK 9, which moved MetaTables out of the SDK
into the separate mainsequence-metatable client (imported as metatables).
See
ADR 0043.
Changed
- Breaking: requires
mainsequence>=9.0.2,<10andmainsequence-metatable>=0.1.6,<0.2. SDK 8 and earlier are unsupported; stay onms-markets1.x for SDK 8 projects. Dependent packages declarems-markets>=2,<3.mainsequence-metatablerequires SQLAlchemy 2.1, whose PostgreSQL compiler renders typed bind casts such as%(direction_0)s::SMALLINTin compiled SQL. - Breaking: MetaTables imports moved from
mainsequence.meta_tables,mainsequence.client.metatables,mainsequence.client.dtype_codec, andmainsequence.client.BaseUpdateStatisticsto themetatablespublic exports;mainsequence.meta_tables.time_index_table_updates.<module>moved tometatables.updaters.<module>; migration helpers moved tometatables.migrations; the compiler moved tometatables.compiled_sql.v1. Types in ms-markets signatures (MetaTable,TimeIndexMetaTable,MetaTableCompiledSQLOperation,MetaTableOperationLimits,UpdateStatistics,BaseUpdateStatistics,TimeIndexTableUpdater,TimeIndexTableRef,PlatformManagedMetaTable,PlatformTimeIndexMetaTable, and the updater configuration classes) are now themetatablesclasses. - Breaking:
msm.repositories.base.compile_markets_statement(statement, *, context, operation, models, access)is nowcompile_markets_statement(statement, *, context, operation, dialect=None). Themodels=andaccess=parameters were removed with the SQL operation scope; passing them raisesTypeError. The compiled operation carriesdata_source_uidat top level and has noscope. ms-markets leavescontext.data_source_uidasNone, so the compiler takes the DataSource and the SQL dialect together from the runtime of the MetaTables API that the caller's Organization Environment selects; no API URL or DataSource setting is needed. A runtime without a usable DataSource raisesmetatables.DataSourceResolutionError, and an explicitdata_source_uidthat differs from the runtime is rejected unlessdialect=is also passed for offline compilation. Limits, offsets, statement deadlines, HTTP timeouts, and theselect(read) versus other labels (write) execution semantics are unchanged. - Breaking:
MarketsRepositoryContextno longer accepts or exposesreserved_policyand no longer hasscope_table(...).MarketsMetaTableHandleno longer has thereserved_policyfield,scope_table(...), ormeta_table_uid_for_model(...). Kept:MarketsRepositoryContext(limits=, data_source_uid=, timeout=, namespace=),MarketsRepositoryContext.meta_table_uid_for_model(...),MarketsRepositoryContext.table(...), andMarketsMetaTableHandle.meta_table_uid. - Breaking:
AssetReferenceExecutorandPortfolioReadExecutorcallbacks passed asexecutor=toasset_reference_details(...),asset_reference_details_by_uids(...),latest_portfolio_weights(...), andportfolio_values(...)are called asexecutor(statement)instead ofexecutor(statement, models). - Breaking: MetaTable migration admin commands moved from
mainsequence migrations ...tometatables migrations ... --provider migrations:migration;current --jsonis nowmetatables --json migrations current, andrevisionautogenerates by default. The provider identity is unchanged (packagemsm, namespacemainsequence.markets, version tablems_markets__alembic_version, head0017), and no revision was added. - Breaking: Index FastAPI routes resolve the caller from the
platform-injected
request.state.user(SDK 9 request identity) instead of binding the removed_CURRENT_AUTH_HEADERSand_CURRENT_USERSDK context variables. A request without injected identity is anonymous.
Removed
- Removed
MetaTableOperationScopeTableusage and every scope-only helper and parameter. No compatibility classes or aliases are provided. - Removed the dead
metatable_configured_tablenameusage fromexamples/msm/platform/inspect_markets_metatable_models.py; the helper has nometatablesequivalent and the example already reports the configured physicaltable_name.
Added
- Added the version-matched MetaTables client skills under
.agents/skills/metatables/, copied withmetatables copy-metatables-skills --path ..
Documentation
- Updated the README, getting started, concepts, tutorials, knowledge guides,
FastAPI notes, examples, packaged
ms_marketsagent skills, VS Code tasks and launch configurations, and the managed AGENTS.md section to the SDK 9 andmetatablesimports and commands. Added ADR 0043 and marked ADR 0022, 0024, and 0039 as amended or superseded. - Refreshed the SDK-owned skills under
.agents/skills/mainsequence/with the offline SDK 9.0.2mainsequence code-repository update-agent-skills --path .. The retired SDK MetaTable skills are gone, and platform-owned skills are no longer mirrored into that namespace; the authenticated platform update installs them under.agents/skills/mainsequence_platform/. - Refreshed the repository lock and exported requirements.
[1.0.16] - 2026-09-12
Added
- Added explicit, vectorized
TargetWeightExecutionModelandInstrumentExecutionSpeccontracts for converting the configured signal and rebalance policy into simulated quantities, settlement legs, and restartable execution progress. - Added composable strategy-owned execution cost models and an offline linear perpetual fixture proving variation-margin settlement and pre-execution funding order.
Changed
- Routed opt-in position-aware portfolios through one coordinated
signal-to-
RebalanceStrategysimulation path while leaving the weight-onlyPortfolioRebalanceand commission path unchanged. - Included execution progress in canonical ledger restart state and made exact incremental retries publish no duplicate ledger tail.
- Refreshed the repository lock, exported requirements, and managed platform skills to Main Sequence SDK 8.1.11.
Removed
- Removed the external execution-fact source from position-aware Portfolio configuration and accounting. Portfolios accept no broker/Account execution ingress, compatibility alias, replay lane, or fallback.
Fixed
- Prevented floating-point noise at exact quantity-step boundaries from rounding a mathematically integral target down by one lot.
- Excluded explicitly closed zero-quantity positions from strict mark requirements while preserving their ledger and state rows.
Documentation
- Corrected ADR 0042 and the portfolio accounting guidance to enforce that a
Portfolio is a backtest model with no Account or broker execution inputs.
The configured signal and
RebalanceStrategyare the sole producer of internal simulated execution facts; issue #11 removes the external-execution ingress from1.0.15without a compatibility fallback.
[1.0.15] - 2026-09-12
Added
- Added the opt-in
PortfolioEngineand purePortfolioAccountingreducer, public directly injected lifecycle-event contracts, columnar event batches, explicit execution-fact conversion, and a built-in dividend entitlement and settlement model. - Added strict multi-currency position, cash, and obligation valuation through explicit price and FX observations, plus ledger-derived completed-cash-flow state, and normalized portfolio-value projections.
- Added strict reducer restart from a complete active ledger, including event digest, record-count, state-chain, and opening-configuration validation.
- Added
PortfolioEventLedgerStorage,PortfolioStateStorage, andPortfolioCashFlowsStoragewith provider migration0017. - Added offline EUR-dividend/USD-NAV and custom vectorized cash-flow examples.
Changed
- Added optional
PortfolioBuildConfiguration.accounting_configurationwhile omitting disabled accounting from legacy serialization. The legacyPortfoliosDataNoderejects enabled accounting instead of mixing histories or silently falling back to weight-only valuation.
Documentation
- Added a dedicated position-aware accounting guide covering engine ownership, configuration, execution/dividend/price/FX input grains, ledger records, retry and restart behavior, projections, custom lifecycle models, failure semantics, examples, and the explicit absence of an SDK blocker. Updated the repository portfolio-workflow skill with the same maintenance invariants.
[1.0.14] - 2026-09-09
Added
- Added the installable
msm.api.httpprovider adapter toolkit with strict Command Center collection, discovery, bulk-action preflight, structured error, and owner-scoped observable-operation contracts and helpers. - Added a provider-neutral HTTP contract example covering discovery metadata and operation creation.
Changed
- Moved the reusable
apps/v1resource and bulk-action implementations behind the publicmsm.api.httpimport boundary while retaining compatibility imports for the repository FastAPI app.
Documentation
- Documented provider adapter reuse, error sanitization, operation ownership, and the explicit single-process durability boundary of the bundled in-memory operation store.
[1.0.13] - 2026-09-09
Fixed
- Unified asset-scope mapping identity on canonical
asset_identifierand removedunique_identifierfallback behavior from mapping and object scopes, so inherited asset-indexed validation and portfolio calendar resolution enforce the same payload. Added regressions for #9. - Discarded out-of-range executed-weight seed rows and enforced unique
(time_index, asset_identifier)coordinates before portfolio weight pivots, while preserving one set-based seed lookup. Added regressions for #10.
Documentation
- Documented canonical mapping scopes and defensive portfolio seed validation in the asset guide, portfolio guide, tutorial, and equal-weight example.
[1.0.12] - 2026-09-08
Fixed
- Made strict portfolio valuation require fresh values only where the current or immediately preceding executed holding is nonzero. Unchanged zero-weight assets can remain in complete signal and weight snapshots without blocking valuation, while entry and exit observations remain mandatory. Added regressions that close #8.
Documentation
- Documented exposure-aware strict valuation in the portfolio guide, tutorial, and equal-weight example.
[1.0.11] - 2026-09-08
Fixed
- Preserved
open_time,first_trade_time,last_trade_time, and intradaytrade_dayas timezone-awaredatetime64[ns, UTC]values throughout price interpolation instead of round-tripping pandas 3 microsecond timestamps through unit-ambiguous integers. Added daily and intraday regressions that close #7. - Replaced the deprecated naive
datetime.utcnow()comparison in intraday interpolation with a timezone-aware UTC timestamp.
Documentation
- Documented the interpolated price timestamp contract and the required upgrade-before-scoped-replay order in the portfolio guide, tutorial, and equal-weight example.
[1.0.10] - 2026-09-08
Changed
- Raised the minimum, locked, and exported Main Sequence SDK dependency plus managed repository skill pin from 8.1.7 to 8.1.8.
Fixed
- Restored the complete SDK dimension-query contract on
AssetIndexedDataNode.get_last_observation(...)while retaining validated optional asset scoping. - Fixed portfolio seed observation reads to include complete multidimensional
coordinates such as
(signal_uid, asset_identifier)in one set-based backend request. Added concrete AssetIndexedDataNode regressions that close #6.
Documentation
- Documented the set-based asset seed-read contract in the asset, portfolio, tutorial, and equal-weight example surfaces.
[1.0.9] - 2026-09-08
Documentation
- Corrected the live README, getting-started guide, and FastAPI package contract documentation to state the required Main Sequence SDK 8.1.7 floor; the published dependency metadata already enforced that floor.
[1.0.8] - 2026-09-08
Added
- Added a source-backed trailing-average-daily-volume participation preview example that performs bounded, asset-filtered reads and reports execution quantities, remaining weights, and daily-cap consumption without persisting portfolio state.
Changed
- Raised the minimum, locked, and exported Main Sequence SDK dependency plus managed repository skill pin from 8.1.5 to 8.1.7 so portfolio configuration durations serialize deterministically during updater hashing.
Fixed
- Restored deterministic updater hashing and configuration reconstruction for
CalendarEventSignal.event_offsetandValuationAlignmentPolicy.maximum_stalenessby requiring Main Sequence SDK 8.1.7 or newer. - Added the repository root to pytest's configured import path so executable
examples can be imported by example-focused tests without shell-specific
PYTHONPATHsetup.
[1.0.7] - 2026-09-08
Added
- Added the generic
PortfolioRebalanceupdater andPortfolioRebalanceStateStorageledger for deterministic active-intent, partial-execution, remaining-target, event-provenance, and restart state. - Added
PortfolioCalendarEventsandPortfolioCalendarEventsStorageso calendar-relative strategies consume an explicit published schedule rather than reading or generating dates behind the dependency graph. - Added supported
TimeWeighted,VolumeParticipation, andLiquidityConstrainedstrategies driven by observed bars, volume, and available liquidity. - Added
TrailingAverageDailyVolumeParticipation, which estimates a bounded per-asset daily notional cap from completed historical daily VWAP and volume while executing only at observable intraday prices and volumes. - Added static migration
0016for calendar-event and rebalance-state storage; it also provisions the previously declared portfolio-analytics storage.
Changed
- Replaced the fixed
execution_timestamps(...)/apply_rebalance_logic(...)strategy API with declared dependencies, required input contracts, strategy-owned event selection, and deterministic per-event state transitions. This is a breaking portfolio execution contract change. - Added the optional
prepare_execution_context()strategy hook and indexed signal/event preparation so rolling inputs are computed once rather than rescanned for every event. - Converted
PortfolioWeightsfrom the strategy executor into a pure projection of rebalance-state events that changed executed allocations. - Updated the SDK lock, exported requirements, and managed repository skills to Main Sequence SDK 8.1.5.
Fixed
- Removed central assumptions that every rebalance strategy uses an immediate
signal, one execution valuation frame, or an optional column named
volume. New strategy categories can declare arbitrary typed observed inputs without changing portfolio valuation code. - Preserved unfinished volume- and liquidity-constrained work as
pendingorpartial, with explicit supersession when a newer signal arrives. - Prevented ex-post current-session VWAP from being treated as an execution price or eligible trailing-capacity observation. Daily participation usage now survives same-session restarts and target supersession.
Documentation
- Marked ADR 0040 implemented and updated the portfolio knowledge page, tutorial, and equal-weight example for the general strategy-driven rebalance graph.
- Documented the trailing daily-liquidity strategy and added a focused public configuration example.
[1.0.6] - 2026-09-07
Added
- Added
CalendarEventSignalwith hash-bearing calendar, session, event, offset, cadence, cutoff, and execution-valuation semantics. - Added
PortfolioAnalyticsand separatePortfolioAnalyticsStoragefor consumer-owned reporting resampling with explicit period boundaries and source-observation lineage. - Added a dry-run-first legacy portfolio timestamp repair that validates midnight rows against persisted calendar sessions, applies only a scoped inclusive tail rollback, and requires deterministic portfolio replay.
Changed
- Promoted
PortfolioWeightsto the execution/rebalance updater and madePortfoliosDataNodea valuation-only consumer of canonical executed weights. Canonical execution and valuation timestamps now originate only from signal, persisted calendar, execution-data, or valuation-source observations. - Made
CalendarEventSignal.calendar_identifierrequired and removed silent fallback from persisted calendar lookup to local pandas or synthetic calendars. Missing, ambiguous, and failed governed lookups now fail visibly. - Replaced portfolio-local price-grid controls with strict, bounded per-asset
ValuationAlignmentPolicyas-of selection. Portfolio configuration no longer acceptsportfolio_prices_frequencyorprice_alignment_policy. - Updated the Main Sequence SDK lock and managed repository skills to 8.1.4.
Fixed
- Chunked long-horizon persisted-calendar reads so daily price interpolation remains within governed operation limits.
- Resolved sparse per-asset valuation seeding, midnight relabeling and rerun duplication, and implicit calendar-event timing semantics tracked in issues #2, #3, and #4.
Removed
- Removed unfinished
TimeWeightedandVolumeParticipationstrategies from the supported public strategy surface until their bar-driven execution contracts are implemented.
Documentation
- Added and implemented ADR 0040, establishing separate temporal ownership for portfolio execution, valuation, and analytics.
[1.0.4] - 2026-09-05
Fixed
- Updated portfolio, asset-snapshot, holdings, virtual-fund, and pricing updater calls for the
Main Sequence SDK 8.1 execution contract.
PortfoliosDataNode.run()now forwards onlyupdate_tree,update_only_tree, andoverride_update_stats; the removed scheduler, debug, and force-update controls are no longer exposed or passed to the SDK runner.
[1.0.3] - 2026-09-04
Fixed
- Replaced the per-asset
AssetCategory.replace_memberships()write loop with one governed multi-row upsert followed by one scoped stale-membership delete. Duplicate asset UIDs are normalized before compilation, empty replacements execute one delete, and the public API returns every row from the bulk upsert. This closes #1.
Changed
- Raised the SDK 8 package floor and validated project lock to
mainsequence>=8.0.7, and refreshed the managed Main Sequence repository scaffold from SDK 8.0.7.
[1.0.2] - 2026-08-30
Fixed
- Aligned the FastAPI deployment-contract test with the backend-validated
workflow API
2.1.0declaration and its explicit three-revision retention policy.
[1.0.1] - 2026-08-30
Changed
- Released the first SDK-8-only
ms-marketsmajor version. Package metadata requiresmainsequence>=8.0.4without an exact SDK patch pin; SDK 6 and SDK 7 are unsupported and no compatibility aliases or mixed-version mode are provided. - Completed the SDK 8 hard cut: repository operations use the canonical
CodeRepository and CodeRepositoryBranch ontology, while updater,
configuration, and reference imports use the
mainsequence.meta_tablestime-index-table API, configuration schema version 2, canonical dependency actions, and read-only table references. - Updated
msm copy-msm-skillsfor the SDK 8 scaffold-copy contract and renamed its JSON target field fromprojecttocode_repository. - Completed OpenAPI documentation metadata for every FastAPI v1 operation and tag, added stable tag groups and the canonical source-repository link, documented the composed Asset schemas, and derived canonical row and field descriptions from existing MetaTable metadata so downstream API references do not maintain a duplicate schema-description inventory.
- Replaced every FastAPI v1 list response with the strict Command Center SDK
command-center.resource_collection@v1contract and added authoritativecommand-center.resource_discovery@v1siblings for all 25 collections. Removedresponse_format, DRF-style pagination, and standalone/bulk-actions/discovery paths; embedded authorized bulk actions in resource discovery; added canonical account and pricing-curve detail operations; and pinned conformance tests to the complete Command Center SDK0.1.13schema and fixture bundle. - Added port 3010 to the development-only FastAPI CORS wrapper so the static-site repository's VS Code full-stack debugger can run the local API on port 8001 and frontend on port 3010 together without changing production application middleware.
- Linked the automatically deployed Markets static site to the stable
mainFastAPI ResourceRelease identity and admitted the supportedhttps://*.site-dev.main-sequence.appbrowser origin. API redeployments now rotate behind the same release UID while the Command Center SDK resolves the current opaque RPC endpoint at request time. - Migrated the automatic
mainFastAPI deployment declaration to the current workflow API2.0.0contract and added regression coverage for every-commit redeployment without a caller-selected project image. - Added the canonical
api/main.pydeployment entrypoint for the existingapps/v1application so the platform can discover and automatically deploy the FastAPI resource without moving application logic out ofapps/v1. Added.mainsequence/workflows/fastapi.yamlto redeploy that release on every synchronized commit, and replaced the machine-local Main Sequence SDK source override with the publishedmainsequence==6.0.35package so remote image builds can resolve the dependency. - Added Command Center SDK bulk-action discovery, preflight, and canonical
execution contracts for asset categories, portfolios, and portfolio groups.
Execution now accepts
{selection, options}, rejects the retired FastAPI bulk payloads, and rechecks missing rows and protected portfolio references immediately before deletion. - Restricted the project runtime to Python 3.13, upgraded the Main Sequence SDK,
removed the obsolete SDK upper-version cap, rebuilt the uv lock and local
environment on Python 3.13, and moved documentation and package-publish
workflows to Python 3.13. Refreshed the installed SDK, dependency lock, and
managed Main Sequence skills to
6.0.36. - Replaced the Index calculation architecture with strict
formulaandcustommethods. Formula expressions use typed Asset/Index identifiers, exact source MetaTable UIDs and observables, an allow-listed arithmetic parser, immutable validity versions, exact or bounded backward as-of alignment, and deterministic DataNode dependencies. AddedFormulaIndex, formula catalog routes, mixed-source and Portfolio-to-custom examples, and revision0015; removed operator/leg/resolved-leg registries, observation units, stateful Index performance operators, and all compatibility aliases. Asset and Index now sharelist_related_meta_tables(uid, numeric=True, timestamped=True)and equivalent FastAPI routes backed by paginated, authoritative-FK catalog discovery. Added the immutable PydanticIndexFormulacontract for historical evaluation of caller-supplied Series or DataFrames without a persisted Index or formula-definition UID. - Removed the untyped
Index.providerattribute and its database index through revision0014. Index create/update payloads, catalog search, ordering, FastAPI filtering, detail badges, examples, and OpenAPI no longer expose it, and legacy payloads containingproviderare rejected rather than accepted through a compatibility shim. Source-native facts such as OpenFIGI details remain in their structured metadata payloads. - Hardened the Index catalog and publication path.
Revision
0013adds rebuildable per-Index dataset availability metadata, a historical one-active-definition invariant, and identifier-first canonical lookup indexes. List filters use indexed availability predicates; dataset lists expose populated, compatible-empty, and unavailable states; direct delete impact is typed without a custom deletion workflow; and producers use post-persistence reconciliation. - Replaced asset-biased curve key-node identity with typed
source_reference={"type": "asset" | "index", "identifier": "..."}provenance. Added the sharedFixedIncomeCurveKeyNodebase across deposit, OIS, futures, bond, FX, and cross-currency basis helper models, updated the reconstruction example to demonstrate asset- and index-sourced inputs, and rejected top-levelasset_identifier/index_identifierkey-node fields. - Changed floating-rate bond and swap pricing to resolve projection and
discount curves independently through market-data-set curve bindings.
Projection curves build floating indexes and forecast coupons; discount
curves feed QuantLib discounting engines. The floating bond example, tutorial,
and pricing docs now demonstrate separate projection and discount curves.
Both role bindings must exist even when they point to the same physical
curve_uid. - Changed
MSDataInterface.get_historical_discount_curve_observations(...)to read multi-curve latest-as-of observations through a backend window query instead of scanning full curve history into pandas. - Changed asset snapshot enrichment services to resolve latest rows through backend queries instead of scanning history and choosing the latest row in Python.
- Removed the legacy
MSDataInterfaceprocess-wide latest-observation environment flag; callers must use explicit latest-curve APIs or bounded historical reads. - Added
msm_pricing.pricing_engine.apply_z_spread_to_curve(...)for strict runtime z-spread overlays that matchBond.z_spread(...)'s continuous decimal spread convention without mutating persisted curve observations. - Added
PreparedInstrument.z_spread(...)so valuation-context prepared instruments propagate the selected market-data set and curve quote side when solving z-spreads. - Added
msm_pricing.valuation.build_valuation_position(...)for strict construction of transient valuation baskets from normalized instrument/unit rows. - Added reusable
latest_portfolio_weights(...),portfolio_values(...), andasset_reference_details(...)services for package-owned portfolio output and asset reference reads. - Added
msm_pricing.scenarios.curveswith typed curve scenario models, key-node basis-point bump helpers, runtime scenario curve-handle construction, andprice_curve_scenario(...)delegation to the preparedprice_scenario(...)path. - Added
price_resolved_curve_scenario(...),prepare_resolved_curve_scenario_runtime_overrides(...), andLineCurveResolutionInputfor caller-resolved curve scenarios that already have explicit base/scenario handles per valuation line, with selected base/scenario handle maps exposed for downstream analytics/reporting reuse. - Added
msm_pricing.scenarios.valuationwith typed valuation scenario workflow orchestration, partial-success line pricing, line/carry impacts, optional analytics and cashflows, observed dirty-price z-spread overlays, and an offline workflow example. - Added
msm_pricing.analytics.spreadswith cross-asset spread primitives, fixed-income DV01 spread metrics, optional dependency diagnostics, and an offline fixed-income spread analytics example. - Added
msm_pricing.pricing_engine.curveswith generic QuantLib rate-helper specs/builders, helper-key-node adapters, helper-based curve reconstruction, and curve observation export, plus resolver/scenario support forbuilder_type="rate_helper_curve"without importing connector-specific code. - Extended generic OIS helper reconstruction to expose QuantLib OIS
schedule/convention fields and to require persisted
builder_payload.helper_schema="rate_helpers@v1"for helper-based curve adapters. - Added generic interest-rate futures helper reconstruction with
sofr_future_rate_helperkey-node support and explicit futures price-unit validation. - Added generic zero-coupon and fixed-rate bond helper reconstruction under
msm_pricing.pricing_engine.curves, including bond-helper key-node parsing,rate_helpers@v1reconstruction support, observation export tests, and strict diagnostics for unsupported yield shocks on price-quoted bond helpers. - Added generic cross-currency helper reconstruction under
msm_pricing.pricing_engine.curves, including FX swap helpers, constant-notional cross-currency basis helpers, context/provenance nodes under the existingrate_helpers@v1schema, explicit FX forward-points and basis-spread normalization,JointCalendardecoding, runtime dependency resolvers, and stable helper quote-error diagnostics. - Added
BondInstrumentTermsandbuild_bond_instrument_from_terms(...)for provider-neutral construction of existing zero-coupon, fixed-rate, and floating-rate bond instrument models without source-row parsing or connector dependencies. - Added
CurveObservationExportConfig.from_curve_building_details(...)so helper-reconstructed curves can export compounded annual zero-rate nodes with explicit front-node days and pillar-date inclusion, using term-structure reconstruction functions when QuantLib pillar dates are required. - Extended
price_curve_scenario(...)to forwardovernight_indexandovernight_index_resolverinto helper-reconstructed scenario curve builds. - Updated swap and floating-bond scenario repricing to use explicit
reset_curves(projection_curve=..., discount_curve=...)role handles. - Added
get_many_by_unique_identifier(...)on typed row APIs such asAssetfor batch canonical-identifier resolution. - Added reusable
command_centerhelpers for ms-markets Command Center tabular frames and Asset Monitor workspace documents, plus theapps/v1getAssetMonitorFramereference endpoint. - Added project-local namespace defaults for ms-markets extension models through
__metatable_namespace__plus__markets_base_identifier__, while keepingMSM_AUTO_REGISTER_NAMESPACEas the test/example override. - Added
msm_pricing.api.add_many_pricing_details(...)andAssetPricingDetails.add_many(...)for chunked bulk persistence of asset/instrument pricing details. - Changed pricing-detail batch writes to set per-operation SDK
max_rowslimits from the submitted chunk size instead of carrying a local response pagination loop. - Removed the obsolete pricing schema-creation bootstrap entrypoint; pricing
startup now uses the attach-only
msm_pricing.bootstrap.attach_pricing_schemas(...)API. - Removed the unused
msm_pricing.streamlithelper package and thepricing-streamlitoptional extra. - Added ADR 0033 to document the pricing valuation-position boundary and the
planned replacement for the legacy in-memory
Positionsurface. - Added ADR 0035 to document the target pricing curve identity model, curve building details, and market-data-set curve binding layer.
- Added ADR 0036 to document the prepared pricing valuation context target, including the requirement that portfolio/scenario valuation use bulk SQLAlchemy-backed resolution instead of hiding per-line backend lookup loops behind a public API, and that prepared instruments are copied or wrapped rather than mutating caller-owned instrument objects.
- Added an implementation task plan for reusable valuation input construction, portfolio and asset read services, curve-keyed scenario pricing, and optional fixed-income spread analytics without copying project-local adapter code into the library.
- Added an implementation task plan for upstreaming generic curve
reconstruction and observation export machinery from provider connector code
into
msm_pricing.pricing_engine.curves. - Implemented
PricingValuationContextwith a publicPreparedInstrumentwrapper, frozenPricingValuationContextSpecinput contract, fixed prepared-instrument universe, package-level exports, context-awareValuationPositionmethods,price_scenario(...), set-based row API helpers for pricing market-data bindings, index rows, index convention details, curve bindings, curves, and curve-building details, bulk curve/fixing observation reads, context-owned QuantLib curve handles/indexes, hot-loop resolver injection for prepared floating-rate bond pricing, and a runnable mock curve/fixing valuation-context example. - Implemented ADR 0035 phase-one pricing curve infrastructure with
CurveBuildingDetails,PricingMarketDataSetCurveBinding, nullable legacyCurve.index_uid, resolver cutover to explicit curve bindings, and Alembic revision0007. - Replaced the legacy in-memory
msm_pricing.Positionexport withValuationLineandValuationPositionfor explicit instrument-plus-units valuation. - Added
msm_pricing.api.load_instruments_from_assets(...)for chunked current-instrument loading from asset rows, and documented the account and portfolio normalization boundary for valuation baskets. - Added
MSDataInterface.get_latest_discount_curve(...)for explicit latest discount-curve lookup by curve identity. - Added
DiscountCurvesStorage.key_nodesand rowmetadata_jsoncolumns, withkey_nodestreated as producer-owned JSON construction provenance at publisher/API boundaries and compressed text at rest. - Added the optional
msm_pricing.data_nodes.CurveKeyNodehelper as the recommended key-node shape, including raw quote fields and yield-nativeyieldserialization for discount-curve producers. - Added
DiscountCurvesNode.normalize_key_nodes(...)andset_key_nodes_validator(...)so curve DataNode producers can enforce source-specific key-node provenance schemas without tightening the shared storage contract. - Tightened
DiscountCurvesStorage.curveto a required non-null payload and made discount-curve builders reject missing, null, or empty curve mappings. - Added observation-level discount-curve reads carrying
nodes,key_nodes, andmetadata_json, and exposed those provenance fields in the pricing curve API response. - Refactored the
migrations:migrationprovider, Alembic environment, model registry, and dynamic portfolio example provider onto the SDK-owned MetaTable migration helpers, with revision directories treated as generated Alembic output rather than pre-existing documentation state. - Renamed account allocation APIs and schemas around their actual domain:
AccountModelPortfoliobecameAccountAllocationModel,AccountTargetPortfoliobecameAccountTargetAllocation, and the related fields now useaccount_allocation_model_uidandaccount_target_allocation_uid. - Moved
PortfolioTableidentity and account target-position storage into coremsm;msm_portfoliosnow owns portfolio calculation workflows, while coremsmowns virtual-fund identity, virtual-fund holdings storage, and account allocation planning. - Added the account holdings to virtual-fund allocation planner with
proportional_attributionandstrict_feasiblepolicies, plus an apply step that converts feasible plans intoVirtualFundHoldingsStorageframes. - Extended the account virtual-fund planner with deterministic
position_set_uidinput resolution, notional target conversion through the valuation resolver, deterministic virtual-fund identity helpers, and resolver-level tests plus a dry-run-first account virtual-fund allocation example. - Moved virtual-fund knowledge documentation under the Accounts section as a standalone account allocation document.
- Reorganized DataNode storage contracts by concept: account storage now lives
under
msm.data_nodes.accounts, asset storage undermsm.data_nodes.assets, execution storage undermsm.data_nodes.execution, and portfolio/pricing storage under their matching concept packages. - Renamed the one-pass account and portfolio example to
examples/msm/accounts/account_portfolio_full_workflow.pyand moved the PyCharm run configuration under Accounts because the workflow prepares the reusable portfolio sleeve and then publishes account target positions and holdings. The same full workflow now exposes the virtual-fund allocation extension through dry-run and apply flags. - Added the
apps/v1target-allocation candidate search endpoint for account target-position assignment, returning one paginated asset and portfolio candidate list backed by a compiled MetaTable read. - Added the
apps/v1account target-position write endpoint, deriving parent allocation rows from the account uid and replacing target-position snapshots through one scoped MetaTable upsert operation. - Tightened account target-position validation so portfolio target rows cannot
use
single_asset_quantity. - Tightened
PortfoliosDataNode.run(update_pointers=True)so portfolio pointer updates use explicit DataNodeUpdate UIDs, preserve the existing executed weights pointer when no new weights are produced, and no longer cache a hiddenPortfolioWeightshelper on the portfolio node. - Changed portfolio update-window calculation so the start date comes from this
portfolio's own
PortfoliosStorage.portfolio_identifier, and valuation-source coverage is applied only after reading the actual signal frame. - Added the
apps/v1pricing curve registry list endpoint backed bymsm_pricing.api.Curveand the shared limit-offset pagination envelope. - Added the
apps/v1index delete-impact preflight endpoint so clients can inspect restrictive dependencies, cascade effects, and SET NULL effects before calling the individual index delete route. - Added the FastAPI v1 reusable delete-impact contract and migrated the index
preflight route to the shared
DeleteImpactResponseserializer before additional delete routes copy the index-specific shape. - Added the FastAPI v1 curve-selection reverse lookup endpoint for pricing
curves, removed the curve list
index_uidfilter, and changed index delete-impact to countPricingMarketDataSetCurveBindingindex selectors. - Clarified missing discount-curve API errors so a curve with registry and
market-data binding but no published
DiscountCurvesStorageobservations is reported as missing data, not a generic latest-observation lookup failure. - Changed pricing curve construction to honor
CurveBuildingDetails.interpolation_methodwith native QuantLib curve constructors and reject deprecated methods such aslog_linear_zeroandMonotonicLogCubicDiscountCurve. - Promoted virtual-fund allocation strategy to the first-class
VirtualFundHoldingsStorage.allocation_strategycolumn; low-level explicit publications writeexplicit, and planner-applied rows write the allocation policy mode. - Refactored portfolio construction to consume an explicit
valuation_source_instanceinstead of havingPortfoliosDataNodeconstructInterpolatedPricesfrom portfolioAssetsConfiguration/PricesConfiguration, and updated the equal-weight portfolio example to show the explicit source valuations -> interpolation when needed -> signal -> portfolio dependency graph. - Replaced deprecated builder terminology with portfolio construction wording across README, portfolio docs, ADRs, and internal portfolio logger helper names.
- Changed core portfolio storage identity so portfolio weights, values, FastAPI
latest-weight reads, delete cleanup, and account virtual-fund expansion use
PortfolioTable.unique_identifierasportfolio_identifier; optionalpublished_index_uidremains publication metadata only. - Added nullable
PortfolioTable.signal_uidas a foreign-key pointer toSignalMetadataTable.signal_uid; portfolio workflow pointer updates now persist the resolved signal UID, and portfolio signal-weight API reads use that first-class pointer instead of inferring from shared storage. - Changed portfolio core construction to consume
valuation_source_instanceplus arbitraryvaluation_column: str, replacing the OHLC-boundprice_source_instanceandPriceTypeNamesprice-column contract while keeping bar-specific helpers in contributed price workflows. - Added core portfolio group MetaTables, typed row helpers, FastAPI v1 routes,
docs, examples, and tests for many-to-many portfolio classification through
PortfolioGroupTableandPortfolioGroupMembershipTable. - Extended the full account portfolio example to assign the generated target
sleeve portfolio to an example
PortfolioGroupthrough the public portfolio group API. - Changed portfolio execution to raise a clear calendar materialization error when the rebalance calendar has no sessions for the requested update range, instead of reporting a misleading empty portfolio-weight no-op.
- Changed
msm copy-msm-skillsto delegate its filesystem copy mechanics to the Main Sequence SDK scaffold-skill helper while keeping the same public command UX. Successful copies now write.agents/skills/ms_markets/PINNED_FROM.txt.
Fixed
- Fixed the
apps/v1asset-category detail endpoint soresponse_format=frontend_detailreturns membership-backed detail metadata, includingnumber_of_assetsand the nested asset-listcategories__uidfilter, instead of a bareAssetCategoryrow. - Fixed category-filtered asset lists so
categories__uidresolves membership asset UIDs directly instead of filtering only the first scanned asset page. - Fixed portfolio value row normalization so
PortfoliosDataNoderesolves a real portfolio identifier instead of stringifying its_unique_identifiermethod, and declared thePortfoliosStorage.portfolio_identifierforeign key toPortfolioTable.unique_identifier. - Reworked pricing-details writes so user-facing instrument attachment upserts
AssetPricingDetailsStorage; calls withoutpricing_details_dateusenow()and updateAssetCurrentPricingDetailsTable, while calls with an explicit date upsert only that timestamped snapshot. - Clarified account and portfolio example console output with section titles, corrected portfolio workflow step numbering, and cleaner virtual-fund allocation frame rendering.
- Fixed account virtual-fund planning for portfolio targets so portfolio
sleeves expand from the latest
PortfolioWeightsStoragesnapshot at or before valuation time instead of requiring exact timestamp equality. - Normalized
InterpolatedPrices.update()output time indexes and timestamp columns back todatetime64[ns, UTC]so backend-read microsecond timestamps do not fail SDK DataNode update validation. - Fixed the equal-weight portfolio schema-preparation workflow so it derives the
dynamic revision from the active migration namespace and runs the dynamic
provider upgrade before
--run-after, even when a stale metadata row already exists for the configured interpolation table. - Fixed
PortfoliosDataNodeforced reruns when the latest stored portfolio value is already ahead of usable valuation-source coverage; the portfolio update now returns no new rows before calling calendar scheduling with a reversed date range. - Fixed
ImmediateSignalso portfolio valuation sources only need the configured valuation column; missingvolumenow produces nullable portfolio-weight volume fields instead of failing the rebalance calculation. - Fixed
msm_pricing.api.add_pricing_details(...)so omittingpricing_details_datedelegates the no-date current-update behavior toAssetPricingDetails.add(...)instead of pre-filling a timestamp too early. - Fixed explicit-date pricing detail writes so current pricing details are updated when no current row exists, when the new date is newer than current, or when the same timestamp is being replaced.
- Fixed portfolio update-window selection so source valuation coverage is evaluated only for assets required by the portfolio, instead of taking the oldest progress timestamp across every asset in a large upstream valuation table.
- Fixed portfolio update-window selection for
APIDataNodevaluation sources by loading the API source table update statistics before required asset progress is evaluated. - Made portfolio update-window selection strict when no required asset scope can be determined, instead of falling back to table-wide source progress.
- Fixed portfolio output progress lookup so a shared
PortfoliosStoragetable-wide max from anotherportfolio_identifiercannot move the current portfolio's update start date. - Fixed contributed portfolio signal cursors so shared
SignalWeightsStorageprogress from anothersignal_uidcannot move the current signal's source window.
Removed
- Removed the internal markets MetaTable catalog table, generic
/api/v1/catalogroutes, catalog service layer, and migration catalog refresh hooks. Runtime attachment now stays on direct backendMetaTable/TimeIndexMetaTablelookup by SQLAlchemy table name.
[0.0.39] - 2026-06-06
Highlights
- Split the library into clear package boundaries:
msmfor core market data,msm_portfoliosfor portfolio and virtual-fund workflows, andmsm_pricingfor pricing instruments, pricing market data, curves, fixings, and QuantLib-backed engines. - Completed the storage-first DataNode architecture: DataNode outputs are now
backed by
PlatformTimeIndexMetaTablestorage classes, with schema, dtypes, index grain, metadata, and foreign keys owned by SQLAlchemy/SDK table contracts instead of DataNode-side mirrors. - Moved MetaTable schema lifecycle to the SDK-managed Alembic provider flow and made runtime startup attach to already-registered tables by physical table name rather than using the maintenance catalog as runtime control.
- Reworked portfolio examples into explicit schema-preparation and runtime stages so configured interpolation storage is registered before normal portfolio execution.
- Added cohesive account, asset, portfolio, and pricing documentation, examples, and packaged agent skills that reflect the current package boundaries.
Changed
- Reorganized examples under
examples/msm/,examples/msm_portfolios/, andexamples/msm_pricing/; reorganized knowledge docs under the same package boundaries. - Standardized asset extension naming: public API rows use domain names such as
Bond,Future, andCurrencySpot, while one-to-one MetaTables use<Domain>AssetDetailsTablewithasset_uidas the primary key and FK toAssetTable.uid. - Normalized asset-indexed storage identity columns to explicit names such as
asset_identifier,index_identifier,curve_identifier, andportfolio_identifier, while preserving unique MetaTable business keys such asAssetTable.unique_identifier. - Updated markets, portfolio, and pricing bootstraps to use
start_engine(...)as the public runtime attachment surface. - Replaced deprecated SDK foreign-key helper declarations with normal
SQLAlchemy
ForeignKey(...)declarations. - Added inline SQLAlchemy column labels and descriptions across built-in MetaTables and storage tables.
- Reworked accounts around
Account,AccountGroup,AccountAllocationModel,AccountTargetAllocation,PositionSet, and storage-backed holdings and target positions. - Reworked virtual funds as account-owned allocation views instead of synthetic asset rows.
- Reworked pricing market-data configuration around UID-backed market-data sets and bindings, plus index convention details, index fixings, and curve rows.
- Moved QuantLib pricing engine code under
msm_pricing.pricing_enginesomsm_pricing.modelsremains MetaTable-only. - Raised the Main Sequence SDK dependency floor to
mainsequence>=4.3.8.
Fixed
- Fixed runtime table attachment to resolve
MetaTableandTimeIndexMetaTableresources through POST body filters on physical table names. - Fixed configured
InterpolatedPricesstorage identity so schema preparation and runtime construction derive the same dynamic table from registered source TimeIndexMetaTable UID, source cadence, upsample frequency, and interpolation rule. - Fixed stale source-cadence handling in the equal-weight portfolio schema-preparation workflow.
- Fixed string asset scopes in
InterpolatedPrices.update()so portfolio configurations using asset identifiers work consistently. - Fixed account holdings validation for signed quantity exposure through
quantity * direction. - Blocked
msm copy-msm-skills --path .from running inside the ms-markets source checkout.
Removed
- Removed legacy DataNode schema-bootstrap/fake-row APIs, DataNode-side dtype maps, record definitions, duplicate index-name constants, and compatibility shims that mirrored storage metadata.
- Removed the local
msm migrationscommand group and old migration runner in favor of the SDK Alembic provider flow. - Removed duplicated row-oriented execution fact MetaTables and APIs; execution facts are now storage-first.
- Removed obsolete asset reference-list, pricing, portfolio, account, execution, and utility shims that no longer match the current package boundaries.
- Removed core dependencies that now belong to optional extras, including
QuantLib under
pricingand FastAPI/Uvicorn underpublic_api.
[0.0.1] - 2026-05-25
Added
- Scaffolded the
ms-marketsPython project with the import packagemsm. - Added MkDocs documentation, ADRs, tutorial scaffold, and GitHub Pages deployment workflow.
- Migrated market-domain code from the SDK into
src/msm. - Migrated market-domain examples into
examples/. - Migrated market-domain agent skills into
.agents/skills/. - Added a future CLI package scaffold under
src/cli. - Added the initial
docs/knowledgeconcept documentation area formsmpackage concepts. - Added Apache-2.0 licensing metadata and the full project license.
- Added the
.agents/skills/library_maintenanceOpen Agent skill to enforce library maintenance workflows across implementation, documentation, examples, tutorials, changelog, and validation.
Changed
- Moved asset DataNode schemas from the obsolete
msm.assetspackage boundary intomsm.data_nodes.assets. - Moved OpenFIGI provider helpers into
msm.services.assets.openfigiand kept asset identity on themsm.models.assets.AssetMetaTable model. - Made
msm.servicesandmsm.data_nodespackage exports lazy so provider helpers and lightweight package imports do not initialize unrelated platform dependencies. - Reworked the README into the public project overview, including logo, badges, documentation map, quick start, development commands, metadata, and license information.
- Made README links PyPI-safe by pointing package-page readers to the public documentation site and GitHub project files.
- Added explicit source distribution include rules so PyPI source artifacts do not ship local IDE, workflow, or agent-maintenance files.
- Declared the first release version directly in
pyproject.tomlas0.0.1. - Refactored instrument valuation code into
msm_pricing. - Renamed pricing model helpers from the old
pricing_modelspackage tomsm_pricing.models.
Removed
- Removed migrated market-domain code, examples, and skills from the SDK tree.