Skip to content

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. For PortfolioEventLedgerTS that 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.policy and the Main Sequence Constant MARKETS_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 the MainSequenceMarkets branch, and every caller the API admits may write. registry_write still 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_rows copies the rows of some keys that a target table lacks from another table of the same contract, through the TimeIndexRowsCopy updater, and verifies every key; a second pass fills only the gaps. TableSeriesMove, msm_portfolios.services.series_moves PortfolioSeriesMove and SignalSeriesMove move a series and roll it back, including the catalog and signal-binding calls in a fixed order, and run_series_moves / msm series move|rollback run a provider's moves. A move refuses, before switching the provider, a signal without a SignalMetadata row; a portfolio rollback keeps the binding of a signal that did not move with it (PortfolioDatasets.unregister(..., unbind_signal=False)); moves take keys_per_read and deadline_seconds; msm series passes rollback= to a callable that accepts it.
  • Remote reads and lifecycle calls providers need (ADR 0047): filter and count take <field>__gte, __gt, __lte and __lt range bounds (msm.repositories.crud range_filters); AssetSnapshots.latest returns each asset's latest snapshot by identifier, uid or ticker (msm.services.assets.asset_identifiers_by_ticker); PortfolioDatasets.register_signal binds any signal's weights instance; FormulaIndex.activate_definition and retire_definition back activate()/retire(); GET /portfolio/values/ takes offset and MarketsClient.portfolio_values pages past 5,000 rows. CurrencySpot and Future gain upsert_many and filter; AccountHoldingsSnapshots.get_many returns several snapshots in one call (msm.services.get_account_holdings_snapshots_response); PortfolioDatasets.unregister removes a catalog row for a rollback, and unregister_signal clears one signal's instance binding.
  • Provider time series (ADR 0047): msm.storage_instances.configured_time_index_instance builds 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_storage takes namespace, storage_app and base, and InterpolatedPrices takes storage_namespace, storage_app and storage_base, without changing update_hash. msm_portfolios.api.datasets.PortfolioDatasets.register/reconcile/get run 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), and filter(...) with order_by, offset and <field>__in. msm.repositories.crud.search_model gains order_by. AccountHoldingsSnapshots.publish/get and AssetSnapshots.publish publish 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 on mainsequence.markets. Runtime-backend processes attach foreign-key targets as before.
  • msm.client and the remote row backend (ADR 0047, decision 2). With use_remote_backend(MarketsClient.from_environment().backend) or MSM_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 on mainsequence.markets. A provider's own row classes keep the runtime backend. The client discovers the api release of the MainSequenceMarkets repository in the caller's Environment and authenticates with its release token; MARKETS_API_URL and MARKETS_API_TOKEN select a local API. New routes GET /rows/ and POST /rows/{resource}/{operation}/ serve it; writes go through the registry write policy. MarketsClient.portfolio_values and portfolio_weights read catalogued portfolio time series.
  • Registry write policy (ADR 0047, decision 3). apps.v1.policy runs before every registry_write service: an application (workload identity) may create, update or delete registry rows only when the Main Sequence Constant MARKETS_REGISTRY_WRITERS lists its User uid for that resource or for "*"; other applications get 403. 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 returns 503. The Markets workload needs reader on 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, PortfolioCalendarEventsTS and PortfolioEventLedgerTS are storage contracts with the factories configured_portfolio_rebalance_state_storage, configured_portfolio_calendar_events_storage and configured_portfolio_event_ledger_storage. PortfoliosUpdater takes weights_output_table= and rebalance_output_table= for the PortfolioWeights and PortfolioRebalance updaters it builds, and PortfolioWeights takes rebalance_output_table=. Output tables do not enter update_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, PortfolioWeightsTS and SignalWeightsTS are storage contracts with instances (ADR 0047, decision 5). msm_portfolios.data_nodes.contract_instances adds configured_portfolios_storage, configured_portfolio_weights_storage and configured_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, mirroring IndexDatasetAvailability. SignalMetadataTable.meta_table_uid records the signal's instance. Alembic revision 0021 creates the table and the column; no existing table, column or row changes.
  • msm_portfolios.services.portfolio_datasets adds register_portfolio_datasets, reconcile_portfolio_dataset_availability, list_portfolio_dataset_states and verify_contract_instance. Registration verifies each declared table against the contract; reconciliation aggregates each instance once for all of its portfolios and records unreadable instances as unavailable.
  • apps.v1.identity adds acting_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, and None outside a request. registry_write wraps 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 the apps.v1.identity logger 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/ and PATCH /api/v1/account/{uid}/ (account create and update over msm.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 over FormulaIndex, previews as core.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/ and GET /api/v1/portfolio/weights/ multi-portfolio frames grouped by catalogued table; and POST /api/v1/portfolio/{uid}/datasets/, GET /api/v1/portfolio/{uid}/datasets/ and POST /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 accept include=<sidecar MetaTable uid> and attach provider sidecar rows under includes, resolving the sidecar's foreign key to the core uid from the MetaTables catalog and reading each sidecar once (ADR 0047 include hydration; the Markets workload needs data_viewer on the sidecar).
  • A design note for the contracts package split and msm.client (ADR 0047, decision 2) under docs/planning/implementation_tasks/; the README now describes msm.client as planned rather than shipped.
  • The markets-api resource in .mainsequence/workflows/ms-markets-api.yaml declares acts_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 the markets-api resource fail before it deploys.
  • tests/identity/test_pinned_identities.py pins the identities that a rename or a module move would rotate: the physical table name and MetaTable identifier of every library-owned model, the module:qualname of every shipped TimeIndexTableUpdater and TimeIndexTableUpdateConfig subclass (MetaTables hashes both into each producer's update_hash), and the signal_uid and 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.identity keeps the identities ms-markets derives stable when an updater or configuration class moves. compute_signal_uid, compute_portfolio_configuration_hash and the new msm_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 0022 adds holdings_storage_table_uid, source_storage_table_uid, portfolio_weights_table_update_uid, signal_weights_table_update_uid, portfolio_table_update_uid and an indexed storage_table_uid next to the pre-3.0 *_data_node_uid columns 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-preflight helps host projects move to the 3.0 names. scan lists pre-3.0 import paths, class names and UID field names with their replacements, including getattr(..., "<pre-3.0 field>", default) calls that 4.0 would turn into silent defaults, and exits 1 while any remain. rotation module:callable reports each updater's new and pre-3.0 update_hash. account-uids classifies 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_nodes and msm_pricing.data_nodes are now msm.time_index, msm_portfolios.time_index and msm_pricing.time_index, and msm_portfolios.contrib.prices.data_nodes is msm_portfolios.contrib.prices.updaters. *DataNode updaters are *Updater, *DataNodeConfiguration classes are *UpdaterConfiguration, TargetPositionsDataNodeConfiguration is TargetPositionsConfiguration, and DiscountCurvesNode and FixingRatesNode are DiscountCurvesUpdater and FixingRatesUpdater. Storage classes, physical table names and MetaTable identifiers are unchanged. The asset-indexed skill folder is now assets/asset_indexed_updaters; re-run msm copy-msm-skills to 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 new TimeIndexTableUpdate on 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.identity maps 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_uid and portfolio_table_update_uid (Portfolio), and storage_table_uid (PricingMarketDataSetBinding and the curve and resolve responses). PricingMarketDataConfiguration.data_node_uids is storage_table_uids, PricingMarketDataSetBinding.resolve_data_node_uid is resolve_storage_table_uid, direct_data_node_uid_for is direct_storage_table_uid_for, and the virtual-fund allocation methods take updater= instead of data_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 is storage_table_uid. Missing-curve messages call the bound UID a storage table instead of a TimeIndexTableUpdater.
  • portfolio_values, latest_portfolio_weights and the new signal_weights read in msm_portfolios.services.portfolio_reads resolve each portfolio's table from the catalog and read it by uid through TimeIndexTableRef, filtered by portfolio_identifier or signal_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_weights gains order, and the reads accept a dataset_reader for tests. The portfolio values, weights and signal-weight API routes use these reads. The apps/v1 runtimes attach PortfolioDatasetAvailability.
  • ms-markets requires mainsequence-metatable>=0.1.57,<0.2 (was >=0.1.51). 0.1.57 is the first MetaTables release that computes the update_hash of an updater whose configuration holds a datetime.date or datetime.time.

Deprecated

  • The pre-3.0 import paths msm.data_nodes, msm_portfolios.data_nodes, msm_pricing.data_nodes and msm_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 a DeprecationWarning at the importing line. The pre-3.0 class names, such as AssetIndexedDataNode, PortfoliosDataNode and DiscountCurvesNode, resolve from those paths and from msm_portfolios with 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_uid and data_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 a DeprecationWarning. data_node_uids, resolve_data_node_uid, direct_data_node_uid_for, data_node= and msm.settings.markets_data_node_identifier are deprecated aliases. ms-markets 4.0 removes them.

Fixed

  • Every hosted rollout since 2026-10-21 stopped at the migrate-markets Job with No 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 through msm.distribution.package_version(), which falls back to the checkout's pyproject.toml when the distribution is not installed.

  • requirements.txt, the only dependency input of a Main Sequence image, still pinned mainsequence-metatable==0.1.51 after the floor moved to 0.1.57, so the image lacked metatables.envelope_contract. It is regenerated with mainsequence code-repository sync, and a test now fails when its pins differ from uv.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_tables and Alembic autogenerate failed with NoReferencedTableError. 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 defined once 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_engine accepts such instances: they are not MarketsBase subclasses but carry the Markets mixins.

  • The portfolio guide's provider example passed namespace= to PortfoliosUpdater, which is the hash namespace and rotates update_hash.

  • Under the remote backend, PersistedCalendarSchedule.schedule (calendar-relative rebalancing) and FormulaIndex.activate()/retire() ran compiled SQL in the calling process and failed; they now run through dispatched row methods.

  • Index.upsert_many now applies Index.upsert's calculation_method guard 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_uid columns are labelled as TimeIndexTableUpdate uids, which is what the portfolio updaters write. PricingMarketDataSetBindingTable.data_node_uid is labelled as the storage table uid it is resolved through. AccountTable.holdings_data_node_uid and AccountHoldingsSetTable.source_data_node_uid describe TimeIndexMetaTable uids, as their original DataNodeStorage descriptions 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.md describes timestamped data in MetaTables terms: a PlatformTimeIndexMetaTable storage class written by a TimeIndexTableUpdater producer, instead of a single DataNode storage contract.
  • include on the by-uid lookups no longer returns application-encrypted sidecar columns. Markets skips every column the MetaTables catalog marks with encryption (MetaTables ADR 0025) and drops any value that is an mt1. encryption envelope, so a provider can grant the Markets workload data_viewer on 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 with AttributeError and 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/ and DELETE /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 new retained_datasets field. The bulk-delete preflight warns about those tables. A catalog row that names the core table counts as core.
  • compute_portfolio_configuration_hash and compute_signal_uid no longer raise TypeError when a configuration holds a datetime.date or datetime.time, such as the execution window of TimeWeighted, VolumeParticipation and TrailingAverageDailyVolumeParticipation. 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, PortfolioWeights and PortfoliosUpdater also compute their update_hash for a portfolio that uses one of these strategies, instead of raising the same TypeError.

[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,<10 and mainsequence-metatable>=0.1.51,<0.2; the lock and exported requirements.txt select mainsequence 9.0.30, mainsequence-metatable 0.1.51 and, through them, mcp 2.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, answered 401 to every signed request; SDK 9.0.25 and 9.0.26 raise when code reads the request identity's team_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-api and migrate-markets declare policy: reader on the MetaTables branch, the conversion of their former level: view.
  • MetaTables access follows its namespace and table roles (MetaTables ADR 0024). On mainsequence.markets the migrate-markets Job holds editor, the markets-api release data_writer, and a person or a people-only Team owner; the namespace's owners grant these in each Environment. The release, migration and FastAPI guides and the packaged metatable_migrations skill describe them, with the roles consuming projects need: editor for migration Jobs that register tables in mainsequence.markets, table editor on their outputs plus data_viewer for updater producers, data_writer for row writers and data_viewer for readers.
  • IndexActor.team_uids is deprecated and empty for HTTP callers, because caller assertions name no Teams. The Index actor never reads the request identity's team_uids; an SDK User still contributes its organization_teams. No Index operation authorizes by Team.
  • Canonical Index dataset discovery no longer reports can_edit=True to the user who registered the table, because registering grants no MetaTables role by itself. can_edit is None; the platform checks edit access when a change runs.
  • get_openfigi_api_key() raises OpenFigiConfigurationError naming value_reader on OPEN_FIGI_API_KEY when 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 declares secrets: [{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-app skill), and removed the retired managed block from AGENTS.md: mainsequence code-repository update no longer exists.

Removed

  • scripts/bootstrap_metatables_access.py and its tests. It called Team bulk-member and MetaTables Reader/Writer routes that no longer exist, and roles replace its Team Writer model. mainsequence.markets exists 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 0020 upgrade. 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 0017 bridge and applied revisions stay unchanged.

[2.2.7] - 2026-10-11

Fixed

  • Restore a forward upgrade for populated PostgreSQL databases at the retired 0017 head, which blocked the Production API rollout. A compatibility anchor and merge revision 0020 join that history with development's 0018/0019 without 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.py gives the deployment's workload Users Writer on the mainsequence.markets MetaTables namespace in one Environment, for an Organization admin to run once from a checkout of development or main. It creates the Team ms-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-run only reports. Without this grant the migration Job could not register tables. In development it got 422 MetaTable is not editable on msm.alembic_version, which a previous runtime identity had registered. See MetaTables#43 and "MetaTables access in each Environment" in docs/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 exported requirements.txt select 0.1.29. Changes in MetaTables 0.1.29 (MetaTables#52):
  • Hosted migrations no longer create application tables in the metatables catalog schema. The migration connection pins search_path=public, the client checks it, and the PostgreSQL version table is always schema-qualified (MetaTables#50). The first ms-markets migration in development, on 2026-10-03, had created all its tables in metatables, 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 in public.
  • 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 exported requirements.txt select 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 503 database_connections_busy with Retry-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 exported requirements.txt select 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.py sets up.
  • A table registered in a namespace the caller already writes gets no grant of its own.
  • A refused registration answers 403 table_not_editable or namespace_not_writable, with the caller's User UID.
  • The vendored MetaTables agent skills are refreshed to 0.1.27. The metatables-migrations skill makes the per-Environment Team a deployment step.
  • Requires mainsequence>=9.0.19,<10 and mainsequence-metatable>=0.1.26,<0.2; the lock and exported requirements.txt select mainsequence 9.0.19 and mainsequence-metatable 0.1.26. MetaTables 0.1.24 and later require mainsequence[mcp]>=9.0.19 and always install fastembed, so onnxruntime, tokenizers, huggingface-hub and mcp are 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 --local and apply the local system migration 0011_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: Bearer token, which is checked against MAINSEQUENCE_ENDPOINT; without one it receives 401.
  • Refreshed the Main Sequence SDK agent skills and the managed AGENTS.md block to 9.0.19, and the MetaTables agent skills to 0.1.26. The 0.1.18 MetaTables skills said registered foreign keys must use RESTRICT or NO 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 applied 0018, 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) in create_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 from request.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 read organization_teams, which a request identity does not have, so an HTTP caller's Teams were always empty.
  • The markets-api release and the migrate-markets Job declare access.branches view 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 with sub_application="portfolios". It discarded the result of .bind() and returned the unbound SDK logger, so msm_portfolios.utils.logger and the msm_portfolios.configuration logger never carried the binding.
  • examples/msm_portfolios/portfolio_equal_weights_prepare_schema.py runs the dynamic Alembic revision and upgrade through the metatables migrations CLI. It invoked python -m mainsequence migrations ..., which the SDK no longer provides, so schema preparation failed unless --check-only was set.
  • Removed a stray module-level developer note from msm_portfolios/configuration.py that referenced the retired SDK data_publishing skill by a local absolute path.

[2.2.5] - 2026-10-04

Fixed

  • TabularFrameResponse and its field, source, time-series and table-visual models omit unset optional fields instead of serializing them as null, which the core.tabular_frame@v1 schema rejects. A plain dump of build_tabular_frame(...) failed the schema on error, meta, source and the field label, provenance, derivedFrom and warnings; only routes declared with response_model_exclude_none=True, as every ms-markets frame route is, returned a valid frame. null cell values in rows are kept. A test fails if any optional field of the bulk-action, resource-collection or tabular-frame contract models serializes as null, other than BulkDeletePreflightResponse.impact, and the Command Center connection contract is validated against the Adapter from API discovery schema.

[2.2.4] - 2026-10-04

Fixed

  • BulkActionDefinition omits tone, confirmation and preflight_endpoint, and BulkActionPreflightResponse omits detail, matched_count, blockers and warnings, when they are unset, instead of serializing them as null. The Command Center SDK accepts these fields only when they are absent or valid, so a discovery route that advertised an action without a tone or confirmation failed 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 no null values 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_rows impact as impact and describe each cascade, SET NULL or SET DEFAULT action in warnings. MetaTables' blockers (the caller cannot write the table, the table does not accept writes, or its DataSource is read-only) are added to blockers and also stop the bulk delete with 409; cascades never block. If MetaTables cannot compute the impact, a warning says so and the delete is not blocked. BulkDeletePreflightResponse and the TableImpact models are exported from msm.api.http, and delete_rows_impact from msm.services.

Changed

  • Requires mainsequence-metatable>=0.1.18,<0.2; the lock and exported requirements.txt select mainsequence-metatable 0.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 exported requirements.txt select mainsequence-metatable 0.1.17. Earlier releases refuse to finalize tables with cascading foreign keys (cascading_foreign_key_unsupported), so the ms-markets provider could not finish migrations 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 the get_impact pre-flight.

Fixed

  • PortfolioEventLedgerTS declares an explicit __storage_layout__ whose lookup index is named portfolio_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_api graph, and say that publishing is a plain git push. Since Main Sequence SDK 9.0.5, mainsequence code-repository sync only refreshes uv.lock, the environment and requirements.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_migrations skills no longer suggest extending the ms-markets revision graph or applying msm_migrations:migration outside the ms-markets deployment.
  • MetaTable registration no longer describes the removed catalog projection hook, and the metatable_migrations skill's project provider example uses the locations metatables migrations scaffold --module derives.
  • Refreshed the MetaTables agent skills to 0.1.14 and the managed AGENTS.md section from SDK 9.0.5; the SDK skill bundle is unchanged.

[2.2.0] - 2026-10-03

Removed

  • Breaking: the msm_command_center package is removed. Import the core.tabular_frame@v1 models and helpers (TabularFrameResponse, TabularFrameMetaResponse, TabularFrameFieldResponse, TabularFrameSourceResponse, build_tabular_frame, build_tabular_field, CORE_TABULAR_FRAME_CONTRACT) from msm.api.http. infer_tabular_field_type is removed.
  • Breaking: build_asset_monitor_frame and build_asset_monitor_workspace_document are removed. getAssetMonitorFrame builds its frame inside apps/v1 and 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 carry x-response-mappings. Command Center SDK 0.1.13 retired response mappings; bind the cashflows/frame/ and net-cashflows/frame/ routes instead.
  • Breaking: getAssetMonitorFrame returns only the uid, unique_identifier, and asset_type columns, and its meta.marketAsset no longer names a tickerField. The removed ticker, name, figi, composite_figi, exchange_code, security_type, security_market_sector, and currency columns were always null: the asset list does not load them.
  • The apps/v1 re-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 the ErrorResponse re-export in apps.v1.schemas.common. Import from msm.api.http.
  • The Command Center Asset Monitor skills are removed.

Changed

  • Adapter from API discovery takes an operation's responseContract only from its x-ui-contract declaration; it no longer infers core.tabular_frame@v1 from a response model named TabularFrameResponse. Every frame route already declares it, so the advertised contracts are unchanged.
  • Requires mainsequence-metatable>=0.1.14,<0.2; the lock and exported requirements.txt select mainsequence-metatable 0.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 development publishes an X.Y.Z.devN build to PyPI. main is protected, and each merged pull request from development publishes the declared X.Y.Z, creates the vX.Y.Z tag and GitHub release, deploys the documentation and returns the next patch version to development. Pushing a v* 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 dev extra adds build, packaging and twine>=7. twine 6 rejects the Metadata-Version: 2.5 that hatchling writes.

Documentation

[2.1.1] - 2026-10-03

Changed

  • Renamed the deployment workflow file from .mainsequence/workflows/fastapi.yaml to .mainsequence/workflows/ms-markets-api.yaml. Its name, resources and execution graph are unchanged.

Fixed

  • api_http_error maps the SDK ConflictError to a non-retryable 409 conflict response with a fixed message, instead of a retryable 503 dependency_unavailable. Fixes #13.

Documentation

  • Aligned the migration docs and examples with the MetaTables 0.1.12 guidance: manual upgrade/downgrade commands target the local runtime (--local), hosted schema changes come from the migrate-markets deployment Job, raw PostgreSQL SQL in a revision must branch on the dialect, and the 2.1.0 0018_initial_schema squash replaces the old revision history. The documented client requirement is mainsequence-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:migration in their own migration Job. The migration docs and the shipped metatable_migrations skill now state that only the ms-markets deployment's migrate-markets Job 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–0017 are 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 to base with 2.0.x installed, then apply 2.1.0 from empty. The provider key, MarketsAlembicVersion and its table are unchanged. The history now builds on the MetaTables local SQLite runtime as well as PostgreSQL (ADR 0045, #12, #15).
  • Breaking: the cli and command_center packages are renamed msm_cli and msm_command_center, and bundled skills ship inside msm_cli/_skills. The wheel installs only msm* packages; the msm console script is unchanged (#14).
  • Requires mainsequence>=9.0.5,<10 and mainsequence-metatable>=0.1.12,<0.2; the lock and exported requirements.txt select mainsequence 9.0.5 and mainsequence-metatable 0.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 applies msm_migrations:migration with metatables.upgrade_application(...); a failed migration blocks the rollout.
  • Migration docs and the shipped metatable_migrations skill scope manual metatables migrations upgrade to the local runtime (--local). Hosted environments are migrated only by the deployment workflow's Job, and applications that deploy code reading ms-markets tables apply msm_migrations:migration in their own migration Job first.

[2.0.2] - 2026-10-02

Changed

  • Breaking: the Alembic migration provider moved from the top-level migrations package to msm_migrations, and the wheel no longer installs a top-level migrations package. Use metatables migrations ... --provider msm_migrations:migration; msm.migrations:migration remains a compatibility alias. The provider key msm:<namespace>, MarketsAlembicVersion, and revisions 0001–0017 are 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 default migrations:versions.

Removed

  • The unreachable versions/default revision directory and the redundant script.py.mako wheel 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,<10 and mainsequence-metatable>=0.1.6,<0.2. SDK 8 and earlier are unsupported; stay on ms-markets 1.x for SDK 8 projects. Dependent packages declare ms-markets>=2,<3. mainsequence-metatable requires SQLAlchemy 2.1, whose PostgreSQL compiler renders typed bind casts such as %(direction_0)s::SMALLINT in compiled SQL.
  • Breaking: MetaTables imports moved from mainsequence.meta_tables, mainsequence.client.metatables, mainsequence.client.dtype_codec, and mainsequence.client.BaseUpdateStatistics to the metatables public exports; mainsequence.meta_tables.time_index_table_updates.<module> moved to metatables.updaters.<module>; migration helpers moved to metatables.migrations; the compiler moved to metatables.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 the metatables classes.
  • Breaking: msm.repositories.base.compile_markets_statement(statement, *, context, operation, models, access) is now compile_markets_statement(statement, *, context, operation, dialect=None). The models= and access= parameters were removed with the SQL operation scope; passing them raises TypeError. The compiled operation carries data_source_uid at top level and has no scope. ms-markets leaves context.data_source_uid as None, 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 raises metatables.DataSourceResolutionError, and an explicit data_source_uid that differs from the runtime is rejected unless dialect= is also passed for offline compilation. Limits, offsets, statement deadlines, HTTP timeouts, and the select (read) versus other labels (write) execution semantics are unchanged.
  • Breaking: MarketsRepositoryContext no longer accepts or exposes reserved_policy and no longer has scope_table(...). MarketsMetaTableHandle no longer has the reserved_policy field, scope_table(...), or meta_table_uid_for_model(...). Kept: MarketsRepositoryContext(limits=, data_source_uid=, timeout=, namespace=), MarketsRepositoryContext.meta_table_uid_for_model(...), MarketsRepositoryContext.table(...), and MarketsMetaTableHandle.meta_table_uid.
  • Breaking: AssetReferenceExecutor and PortfolioReadExecutor callbacks passed as executor= to asset_reference_details(...), asset_reference_details_by_uids(...), latest_portfolio_weights(...), and portfolio_values(...) are called as executor(statement) instead of executor(statement, models).
  • Breaking: MetaTable migration admin commands moved from mainsequence migrations ... to metatables migrations ... --provider migrations:migration; current --json is now metatables --json migrations current, and revision autogenerates by default. The provider identity is unchanged (package msm, namespace mainsequence.markets, version table ms_markets__alembic_version, head 0017), 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_HEADERS and _CURRENT_USER SDK context variables. A request without injected identity is anonymous.

Removed

  • Removed MetaTableOperationScopeTable usage and every scope-only helper and parameter. No compatibility classes or aliases are provided.
  • Removed the dead metatable_configured_tablename usage from examples/msm/platform/inspect_markets_metatable_models.py; the helper has no metatables equivalent and the example already reports the configured physical table_name.

Added

  • Added the version-matched MetaTables client skills under .agents/skills/metatables/, copied with metatables copy-metatables-skills --path ..

Documentation

  • Updated the README, getting started, concepts, tutorials, knowledge guides, FastAPI notes, examples, packaged ms_markets agent skills, VS Code tasks and launch configurations, and the managed AGENTS.md section to the SDK 9 and metatables imports 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.2 mainsequence 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 TargetWeightExecutionModel and InstrumentExecutionSpec contracts 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-RebalanceStrategy simulation path while leaving the weight-only PortfolioRebalance and 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 RebalanceStrategy are the sole producer of internal simulated execution facts; issue #11 removes the external-execution ingress from 1.0.15 without a compatibility fallback.

[1.0.15] - 2026-09-12

Added

  • Added the opt-in PortfolioEngine and pure PortfolioAccounting reducer, 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, and PortfolioCashFlowsStorage with provider migration 0017.
  • Added offline EUR-dividend/USD-NAV and custom vectorized cash-flow examples.

Changed

  • Added optional PortfolioBuildConfiguration.accounting_configuration while omitting disabled accounting from legacy serialization. The legacy PortfoliosDataNode rejects 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.http provider 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/v1 resource and bulk-action implementations behind the public msm.api.http import 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_identifier and removed unique_identifier fallback 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 intraday trade_day as timezone-aware datetime64[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_offset and ValuationAlignmentPolicy.maximum_staleness by 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 PYTHONPATH setup.

[1.0.7] - 2026-09-08

Added

  • Added the generic PortfolioRebalance updater and PortfolioRebalanceStateStorage ledger for deterministic active-intent, partial-execution, remaining-target, event-provenance, and restart state.
  • Added PortfolioCalendarEvents and PortfolioCalendarEventsStorage so calendar-relative strategies consume an explicit published schedule rather than reading or generating dates behind the dependency graph.
  • Added supported TimeWeighted, VolumeParticipation, and LiquidityConstrained strategies 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 0016 for 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 PortfolioWeights from 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 pending or partial, 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 CalendarEventSignal with hash-bearing calendar, session, event, offset, cadence, cutoff, and execution-valuation semantics.
  • Added PortfolioAnalytics and separate PortfolioAnalyticsStorage for 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 PortfolioWeights to the execution/rebalance updater and made PortfoliosDataNode a 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_identifier required 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 ValuationAlignmentPolicy as-of selection. Portfolio configuration no longer accepts portfolio_prices_frequency or price_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 TimeWeighted and VolumeParticipation strategies 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 only update_tree, update_only_tree, and override_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.0 declaration and its explicit three-revision retention policy.

[1.0.1] - 2026-08-30

Changed

  • Released the first SDK-8-only ms-markets major version. Package metadata requires mainsequence>=8.0.4 without 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_tables time-index-table API, configuration schema version 2, canonical dependency actions, and read-only table references.
  • Updated msm copy-msm-skills for the SDK 8 scaffold-copy contract and renamed its JSON target field from project to code_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@v1 contract and added authoritative command-center.resource_discovery@v1 siblings for all 25 collections. Removed response_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 SDK 0.1.13 schema 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 main FastAPI ResourceRelease identity and admitted the supported https://*.site-dev.main-sequence.app browser 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 main FastAPI deployment declaration to the current workflow API 2.0.0 contract and added regression coverage for every-commit redeployment without a caller-selected project image.
  • Added the canonical api/main.py deployment entrypoint for the existing apps/v1 application so the platform can discover and automatically deploy the FastAPI resource without moving application logic out of apps/v1. Added .mainsequence/workflows/fastapi.yaml to redeploy that release on every synchronized commit, and replaced the machine-local Main Sequence SDK source override with the published mainsequence==6.0.35 package 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 formula and custom methods. 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. Added FormulaIndex, formula catalog routes, mixed-source and Portfolio-to-custom examples, and revision 0015; removed operator/leg/resolved-leg registries, observation units, stateful Index performance operators, and all compatibility aliases. Asset and Index now share list_related_meta_tables(uid, numeric=True, timestamped=True) and equivalent FastAPI routes backed by paginated, authoritative-FK catalog discovery. Added the immutable Pydantic IndexFormula contract for historical evaluation of caller-supplied Series or DataFrames without a persisted Index or formula-definition UID.
  • Removed the untyped Index.provider attribute and its database index through revision 0014. Index create/update payloads, catalog search, ordering, FastAPI filtering, detail badges, examples, and OpenAPI no longer expose it, and legacy payloads containing provider are 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 0013 adds 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 shared FixedIncomeCurveKeyNode base 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-level asset_identifier/index_identifier key-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 MSDataInterface process-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 match Bond.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(...), and asset_reference_details(...) services for package-owned portfolio output and asset reference reads.
  • Added msm_pricing.scenarios.curves with typed curve scenario models, key-node basis-point bump helpers, runtime scenario curve-handle construction, and price_curve_scenario(...) delegation to the prepared price_scenario(...) path.
  • Added price_resolved_curve_scenario(...), prepare_resolved_curve_scenario_runtime_overrides(...), and LineCurveResolutionInput for 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.valuation with 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.spreads with 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.curves with generic QuantLib rate-helper specs/builders, helper-key-node adapters, helper-based curve reconstruction, and curve observation export, plus resolver/scenario support for builder_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_helper key-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@v1 reconstruction 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 existing rate_helpers@v1 schema, explicit FX forward-points and basis-spread normalization, JointCalendar decoding, runtime dependency resolvers, and stable helper quote-error diagnostics.
  • Added BondInstrumentTerms and build_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 forward overnight_index and overnight_index_resolver into 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 as Asset for batch canonical-identifier resolution.
  • Added reusable command_center helpers for ms-markets Command Center tabular frames and Asset Monitor workspace documents, plus the apps/v1 getAssetMonitorFrame reference endpoint.
  • Added project-local namespace defaults for ms-markets extension models through __metatable_namespace__ plus __markets_base_identifier__, while keeping MSM_AUTO_REGISTER_NAMESPACE as the test/example override.
  • Added msm_pricing.api.add_many_pricing_details(...) and AssetPricingDetails.add_many(...) for chunked bulk persistence of asset/instrument pricing details.
  • Changed pricing-detail batch writes to set per-operation SDK max_rows limits 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.streamlit helper package and the pricing-streamlit optional extra.
  • Added ADR 0033 to document the pricing valuation-position boundary and the planned replacement for the legacy in-memory Position surface.
  • 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 PricingValuationContext with a public PreparedInstrument wrapper, frozen PricingValuationContextSpec input contract, fixed prepared-instrument universe, package-level exports, context-aware ValuationPosition methods, 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 legacy Curve.index_uid, resolver cutover to explicit curve bindings, and Alembic revision 0007.
  • Replaced the legacy in-memory msm_pricing.Position export with ValuationLine and ValuationPosition for 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_nodes and row metadata_json columns, with key_nodes treated as producer-owned JSON construction provenance at publisher/API boundaries and compressed text at rest.
  • Added the optional msm_pricing.data_nodes.CurveKeyNode helper as the recommended key-node shape, including raw quote fields and yield-native yield serialization for discount-curve producers.
  • Added DiscountCurvesNode.normalize_key_nodes(...) and set_key_nodes_validator(...) so curve DataNode producers can enforce source-specific key-node provenance schemas without tightening the shared storage contract.
  • Tightened DiscountCurvesStorage.curve to 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, and metadata_json, and exposed those provenance fields in the pricing curve API response.
  • Refactored the migrations:migration provider, 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: AccountModelPortfolio became AccountAllocationModel, AccountTargetPortfolio became AccountTargetAllocation, and the related fields now use account_allocation_model_uid and account_target_allocation_uid.
  • Moved PortfolioTable identity and account target-position storage into core msm; msm_portfolios now owns portfolio calculation workflows, while core msm owns virtual-fund identity, virtual-fund holdings storage, and account allocation planning.
  • Added the account holdings to virtual-fund allocation planner with proportional_attribution and strict_feasible policies, plus an apply step that converts feasible plans into VirtualFundHoldingsStorage frames.
  • Extended the account virtual-fund planner with deterministic position_set_uid input 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 under msm.data_nodes.assets, execution storage under msm.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.py and 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/v1 target-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/v1 account 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 hidden PortfolioWeights helper 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/v1 pricing curve registry list endpoint backed by msm_pricing.api.Curve and the shared limit-offset pagination envelope.
  • Added the apps/v1 index 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 DeleteImpactResponse serializer 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_uid filter, and changed index delete-impact to count PricingMarketDataSetCurveBinding index selectors.
  • Clarified missing discount-curve API errors so a curve with registry and market-data binding but no published DiscountCurvesStorage observations is reported as missing data, not a generic latest-observation lookup failure.
  • Changed pricing curve construction to honor CurveBuildingDetails.interpolation_method with native QuantLib curve constructors and reject deprecated methods such as log_linear_zero and MonotonicLogCubicDiscountCurve.
  • Promoted virtual-fund allocation strategy to the first-class VirtualFundHoldingsStorage.allocation_strategy column; low-level explicit publications write explicit, and planner-applied rows write the allocation policy mode.
  • Refactored portfolio construction to consume an explicit valuation_source_instance instead of having PortfoliosDataNode construct InterpolatedPrices from portfolio AssetsConfiguration/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_identifier as portfolio_identifier; optional published_index_uid remains publication metadata only.
  • Added nullable PortfolioTable.signal_uid as a foreign-key pointer to SignalMetadataTable.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_instance plus arbitrary valuation_column: str, replacing the OHLC-bound price_source_instance and PriceTypeNames price-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 PortfolioGroupTable and PortfolioGroupMembershipTable.
  • Extended the full account portfolio example to assign the generated target sleeve portfolio to an example PortfolioGroup through 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-skills to 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/v1 asset-category detail endpoint so response_format=frontend_detail returns membership-backed detail metadata, including number_of_assets and the nested asset-list categories__uid filter, instead of a bare AssetCategory row.
  • Fixed category-filtered asset lists so categories__uid resolves membership asset UIDs directly instead of filtering only the first scanned asset page.
  • Fixed portfolio value row normalization so PortfoliosDataNode resolves a real portfolio identifier instead of stringifying its _unique_identifier method, and declared the PortfoliosStorage.portfolio_identifier foreign key to PortfolioTable.unique_identifier.
  • Reworked pricing-details writes so user-facing instrument attachment upserts AssetPricingDetailsStorage; calls without pricing_details_date use now() and update AssetCurrentPricingDetailsTable, 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 PortfolioWeightsStorage snapshot at or before valuation time instead of requiring exact timestamp equality.
  • Normalized InterpolatedPrices.update() output time indexes and timestamp columns back to datetime64[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 PortfoliosDataNode forced 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 ImmediateSignal so portfolio valuation sources only need the configured valuation column; missing volume now produces nullable portfolio-weight volume fields instead of failing the rebalance calculation.
  • Fixed msm_pricing.api.add_pricing_details(...) so omitting pricing_details_date delegates the no-date current-update behavior to AssetPricingDetails.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 APIDataNode valuation 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 PortfoliosStorage table-wide max from another portfolio_identifier cannot move the current portfolio's update start date.
  • Fixed contributed portfolio signal cursors so shared SignalWeightsStorage progress from another signal_uid cannot move the current signal's source window.

Removed

  • Removed the internal markets MetaTable catalog table, generic /api/v1/catalog routes, catalog service layer, and migration catalog refresh hooks. Runtime attachment now stays on direct backend MetaTable/TimeIndexMetaTable lookup by SQLAlchemy table name.

[0.0.39] - 2026-06-06

Highlights

  • Split the library into clear package boundaries: msm for core market data, msm_portfolios for portfolio and virtual-fund workflows, and msm_pricing for pricing instruments, pricing market data, curves, fixings, and QuantLib-backed engines.
  • Completed the storage-first DataNode architecture: DataNode outputs are now backed by PlatformTimeIndexMetaTable storage 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/, and examples/msm_pricing/; reorganized knowledge docs under the same package boundaries.
  • Standardized asset extension naming: public API rows use domain names such as Bond, Future, and CurrencySpot, while one-to-one MetaTables use <Domain>AssetDetailsTable with asset_uid as the primary key and FK to AssetTable.uid.
  • Normalized asset-indexed storage identity columns to explicit names such as asset_identifier, index_identifier, curve_identifier, and portfolio_identifier, while preserving unique MetaTable business keys such as AssetTable.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_engine so msm_pricing.models remains MetaTable-only.
  • Raised the Main Sequence SDK dependency floor to mainsequence>=4.3.8.

Fixed

  • Fixed runtime table attachment to resolve MetaTable and TimeIndexMetaTable resources through POST body filters on physical table names.
  • Fixed configured InterpolatedPrices storage 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 migrations command 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 pricing and FastAPI/Uvicorn under public_api.

[0.0.1] - 2026-05-25

Added

  • Scaffolded the ms-markets Python project with the import package msm.
  • 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/knowledge concept documentation area for msm package concepts.
  • Added Apache-2.0 licensing metadata and the full project license.
  • Added the .agents/skills/library_maintenance Open Agent skill to enforce library maintenance workflows across implementation, documentation, examples, tutorials, changelog, and validation.

Changed

  • Moved asset DataNode schemas from the obsolete msm.assets package boundary into msm.data_nodes.assets.
  • Moved OpenFIGI provider helpers into msm.services.assets.openfigi and kept asset identity on the msm.models.assets.Asset MetaTable model.
  • Made msm.services and msm.data_nodes package 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.toml as 0.0.1.
  • Refactored instrument valuation code into msm_pricing.
  • Renamed pricing model helpers from the old pricing_models package to msm_pricing.models.

Removed

  • Removed migrated market-domain code, examples, and skills from the SDK tree.