Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 50 additions & 4 deletions packages/loopx-finance-value-discovery/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -667,11 +667,57 @@ the previous revision and use the existing extension rollback/upgrade commands
for controlled recovery. No default node or account is activated by this API.

The existing numeric-accuracy owner now also supplies bounded Decimal parsing;
legacy cash/stock commands retain their input and error contracts. This stage
does not add an App/Lark quantity journey, automatic source interpretation,
source authentication, cash, financial admission or trading permission. Those
consumer/presentation and adoption boundaries remain separately qualified.
legacy cash/stock commands retain their input and error contracts. This arithmetic stage does not interpret or authenticate sources, derive cash,
or grant financial or trading permission. The review wrapper below supplies
the existing App/Lark presentation; source-consumer and financial utility
qualification remain separate.

份额/合约数与货币分别建模,同类别与同持有池的数量核对不推导现金或交易权限。
opening、覆盖、付收方向或精度未知时保留未知,不反推、不补零。合成示例通过
只证明声明下的词法算术;来源认证、PIT、界面/卡片与实际采用另行验收。


### Quantity research review (candidate 0.8.16)

`finance_quantity_research_input_v1` wraps the original quantity input and an
explicit review time, evidence cutoff, publication source/version, supersedes
and review deadline. It returns the complete `quantity_assessment` plus the
existing Investment Research view. Opening/closing stocks, every signed flow,
identity/unit/accuracy, source digest and original capture time remain visible.
Candidate arithmetic, reconciled closing and all holds remain distinct;
missing is not zero, and a conflict never becomes a qualified closing.

```sh
loopx-finance-value-discovery < packages/loopx-finance-value-discovery/examples/quantity-research-v1.json
loopx extension publish-projection loopx-finance-value-discovery investment-research \
--input-json packages/loopx-finance-value-discovery/examples/quantity-research-v1.json \
--execute --format json
loopx-finance-value-discovery render-lark-card \
--input-json packages/loopx-finance-value-discovery/examples/quantity-research-v1.json
```

Open the selected Goal's **Results / 成果** tab, inspect the Quantity review
and its original source/reference details, and use **Refresh / 刷新** after
publication changes. The same revision/hash/deadline is used for a published
Lark draft: pass its receipt to the existing `--published-state-file`, `--goal-id`,
`--extension-revision` and `--payload-sha256` flags. Stale, wrong-Goal and disabled
publications refuse; recovery reads the current reference rather than silently
substituting a result. Card preparation sends nothing and does not renew a
review deadline or grant source, investment, cash or trading admission.

The complete review view supports at most **8 flows** within its existing
12-layer and text limits; larger/unsafe views are refused without truncation.
The arithmetic API still supports 256 flows. Exact long decimal results move
to the arithmetic detail rather than being rounded into a metric cell. Lark's
existing complete-card capacity may also refuse a long view; read the complete
published result in App. Disable using the existing extension lifecycle, and
retain the pinned 0.8.15 wheel/manifest for rollback: old quantity/cash/funding
inputs remain valid, while that old release refuses the new review wrapper.
No private source, account or raw provider response belongs in this public-safe
view. Source mapping, independent consumer adoption and financial utility
remain separate from presentation qualification.

数量复核复用既有成果页与 Lark 发布引用;原始 operands、缺证、冲突及来源时钟
完整保留。长精确数不截断、不四舍五入,超容量明确拒绝。关闭、旧引用与错 Goal
不返回缓存结果;恢复后重新核对当前引用。展示、来源准入、经验采用与金融效用
分别验收;卡片只准备不发送。
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
{
"schema_version": "finance_quantity_research_input_v1",
"goal_id": "quantity-review-demo",
"source_id": "synthetic-quantity-v1",
"source_version": 1,
"supersedes": [],
"point_in_time": "2001-01-05T00:00:00Z",
"evidence_cutoff": "2001-01-04T00:00:00Z",
"review_due_at": "2001-01-06T00:00:00Z",
"quantity_input": {
"schema_version": "finance_quantity_reconciliation_input_v1",
"opening_stock": {
"evidence_ref": "synthetic:opening",
"source_digest": "sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"captured_at": "2001-01-04T00:00:00Z",
"identity": {
"subject_ref": "synthetic:issuer",
"instrument_ref": "synthetic:class-a",
"ownership_scope_ref": "synthetic:single-pool",
"source_version_ref": "synthetic:filing-v1"
},
"unit": {
"measure_ref": "share",
"scale": 0
},
"value": "100",
"accuracy": {
"decimals": "INF"
},
"position": 0,
"aggregation_kind": "stock"
},
"closing_stock": {
"evidence_ref": "synthetic:closing",
"source_digest": "sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"captured_at": "2001-01-04T00:00:00Z",
"identity": {
"subject_ref": "synthetic:issuer",
"instrument_ref": "synthetic:class-a",
"ownership_scope_ref": "synthetic:single-pool",
"source_version_ref": "synthetic:filing-v1"
},
"unit": {
"measure_ref": "share",
"scale": 0
},
"value": "117",
"accuracy": {
"decimals": "INF"
},
"position": 2,
"aggregation_kind": "stock"
},
"flows": [
{
"evidence_ref": "synthetic:acquisition",
"source_digest": "sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"captured_at": "2001-01-04T00:00:00Z",
"identity": {
"subject_ref": "synthetic:issuer",
"instrument_ref": "synthetic:class-a",
"ownership_scope_ref": "synthetic:single-pool",
"source_version_ref": "synthetic:filing-v1"
},
"unit": {
"measure_ref": "share",
"scale": 0
},
"value": "25",
"accuracy": {
"decimals": "INF"
},
"position": 1,
"aggregation_kind": "flow",
"direction": "increase"
},
{
"evidence_ref": "synthetic:disposition",
"source_digest": "sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"captured_at": "2001-01-04T00:00:00Z",
"identity": {
"subject_ref": "synthetic:issuer",
"instrument_ref": "synthetic:class-a",
"ownership_scope_ref": "synthetic:single-pool",
"source_version_ref": "synthetic:filing-v1"
},
"unit": {
"measure_ref": "share",
"scale": 0
},
"value": "8",
"accuracy": {
"decimals": "INF"
},
"position": 2,
"aggregation_kind": "flow",
"direction": "decrease"
}
],
"coverage": {
"complete": true,
"evidence_ref": "synthetic:complete-two-flow-coverage",
"ordering_basis": "source_row_order"
}
}
}
2 changes: 1 addition & 1 deletion packages/loopx-finance-value-discovery/extension.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
schema_version = "loopx_extension_manifest_v0"
id = "loopx-finance-value-discovery"
version = "0.8.15"
version = "0.8.16"
requires_loopx_api = ">=1,<2"
permissions = []

Expand Down
2 changes: 1 addition & 1 deletion packages/loopx-finance-value-discovery/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "loopx-finance-value-discovery"
version = "0.8.15"
version = "0.8.16"
description = "Public-safe finance value-discovery extension for LoopX."
readme = "README.md"
requires-python = ">=3.11"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
assess_funding_event_pair,
)
from .funding_presentation import FINANCE_FUNDING_RESEARCH_INPUT_SCHEMA_VERSION
from .quantity_presentation import FINANCE_QUANTITY_RESEARCH_INPUT_SCHEMA_VERSION
from .quantity_reconciliation import (
FINANCE_QUANTITY_INPUT_SCHEMA_VERSION,
assess_quantity_reconciliation,
Expand Down Expand Up @@ -268,6 +269,7 @@ def run(argv: Sequence[str] | None = None) -> int:
elif schema_version in {
FINANCE_RESEARCH_DASHBOARD_INPUT_SCHEMA_VERSION,
FINANCE_FUNDING_RESEARCH_INPUT_SCHEMA_VERSION,
FINANCE_QUANTITY_RESEARCH_INPUT_SCHEMA_VERSION,
}:
from .dashboard import build_finance_research_dashboard_packet

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,13 @@ def build_finance_research_dashboard_packet(

if payload.get("schema_version") == FINANCE_FUNDING_RESEARCH_INPUT_SCHEMA_VERSION:
return build_funding_event_research_packet(payload)
from .quantity_presentation import (
FINANCE_QUANTITY_RESEARCH_INPUT_SCHEMA_VERSION,
build_quantity_research_packet,
)

if payload.get("schema_version") == FINANCE_QUANTITY_RESEARCH_INPUT_SCHEMA_VERSION:
return build_quantity_research_packet(payload)
record = _record(
payload,
context="input",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from .funding_event import FundingRateKind, assess_funding_event_pair
from .replay import canonical_sha256
from .presentation_validation import evidence_reference, record
from .presentation_validation import public_reference_tree, record


FINANCE_FUNDING_RESEARCH_INPUT_SCHEMA_VERSION = (
Expand All @@ -25,20 +25,6 @@ def _declared(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))


def _public_references(value: Any, context: str = "funding input") -> None:
"""Keep embedded references under the existing publication URL boundary."""
if isinstance(value, Mapping):
for key, child in value.items():
path = f"{context}.{key}"
if child is not None and (key == "ref" or key.endswith("_ref")):
evidence_reference(child, context=path)
else:
_public_references(child, path)
elif isinstance(value, list):
for index, child in enumerate(value):
_public_references(child, f"{context}[{index}]")


def _layer(order: int, label: str, points: list[str]) -> dict[str, Any]:
return {
"id": f"funding-{order}",
Expand Down Expand Up @@ -91,7 +77,7 @@ def build_funding_event_research_packet(payload: Mapping[str, Any]) -> dict[str,
raise ValueError("unsupported funding research input version")
assessment = assess_funding_event_pair(wrapper.get("funding_event_input"))
original = assessment["input"]
_public_references(original)
public_reference_tree(original, "funding input")
decision_at = original["decision_at"]
layers = [
_layer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,17 @@ def evidence_reference(value: Any, *, context: str) -> str:
if any(_is_forbidden_key_name(field) for field in fields):
raise ValueError(f"{context} contains an unsafe evidence reference")
return reference


def public_reference_tree(value: Any, context: str = "input") -> None:
"""Keep embedded references under the existing publication URL boundary."""
if isinstance(value, Mapping):
for key, child in value.items():
path = f"{context}.{key}"
if child is not None and (key == "ref" or key.endswith("_ref")):
evidence_reference(child, context=path)
else:
public_reference_tree(child, path)
elif isinstance(value, list):
for index, child in enumerate(value):
public_reference_tree(child, f"{context}[{index}]")
Loading
Loading