You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
M2-05: Implement quote collection and deterministic selection #26
both success/first wins; both success/second wins; tie;
one timeout; malformed; direction mismatch; amount mismatch;
outside allowlist; all fail; uint256-scale value
验证
pnpm vitest run packages/moss-adapter/test/quote.test.ts
pnpm vitest run packages/moss-adapter/test/selection.test.ts
pnpm --filter @moss-mini-demo/moss-adapter build
pnpm check
Issue #26 is assigned to pillowtalk-Qy and moved to Project In Progress solely to begin planning from this exact main baseline. The first required artifact is a closed Work Plan covering writable paths, public contracts, trust boundaries, tests, non-goals, and verification.
No implementation branch, worktree, commit or PR is authorized before Maintainer SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED. In Progress is not QA PASS, Review, READY_TO_MERGE, Merge Gate, or merge authorization. Do not absorb #27 or later dependent behavior into this plan.
The single Builder slot is #26. Issue #23 remains Ready/unassigned and #27 plus later dependent issues remain Blocked.
This comment is a planning artifact only. It requests a new Maintainer Scope
Gate. It is not implementation authorization, QA PASS, Review, Merge Gate, or
merge authorization.
proposed branch after scope confirmation: codex/issue-26-quote-selection
proposed isolated worktree after scope confirmation: /Users/qy/Documents/moss-mini-demo-issue-26
No branch, worktree, repository file, dependency, lockfile, commit, push, or PR
is created by this comment. If origin/main changes before branch creation,
Builder stops, rescans the new main, and requests a revised Scope Gate.
1. Goal and trust boundary
Add one server-only, deterministic quote collection and candidate-selection
operation to the existing @moss-mini-demo/moss-adapter public entry.
The operation:
validates one chain-143 comparison request and its Maintainer-approved asset
metadata;
requests candidate protocol quotes concurrently;
records one terminal outcome for every candidate protocol;
preserves every acquired RawQuote separately from Mini-Demo-derived
normalization;
selects only among eligible normalized outcomes using the disclosed rule;
returns either one selected candidate or an explicit no-eligible-candidate
result.
A Quote is protocol-selection context only. It is not Capability, simulation,
execution evidence, a best-trade claim, a safety conclusion, authorization, or
a cryptographic binding to any later Capability.
The only approved wording/identifier for the selection rule is DETERMINISTIC_CANDIDATE_SELECTION_V0_1. Public output and tests must not use
“best”, “optimal”, “safe”, “approved”, “executable”, or equivalent language.
2. Exact writable paths
Implementation may modify exactly these 16 repository paths and no others:
packages/moss-adapter/src/types.ts: modified for the exact public and
internal contracts in this plan.
packages/moss-adapter/src/index.ts: modified only to add the exact exports
listed in Section 3.
packages/moss-adapter/package.json: modified only for the two exact
dependencies in Section 4; the package name and sole . export stay
unchanged.
pnpm-lock.yaml: modified only for the moss-adapter importer and canonicalize@3.0.0.
root package.json: no change.
pnpm-workspace.yaml: no change.
packages/moss-adapter/src/errors.ts: no change; per-candidate acquisition
failures are data outcomes, not new thrown MossAdapterError variants.
adapter tsconfig files: no change.
no fixture file is added; tests use inline synthetic data.
Any need for a seventeenth path, a report-schema source edit, a root script
change, a workflow edit, or another dependency is a stop condition requiring a
new Scope Gate.
3. Sole public entry and exact new API
The package keeps exactly one public entry:
@moss-mini-demo/moss-adapter
There is no subpath export and no import from a private src path.
Existing runtime and type exports remain. The only new runtime export is:
No public canonicalization helper, hash helper, comparator, asset lookup helper,
timeout helper, second port, runtime Schema, or source-binding bypass is added.
4. Exact dependency and supply-chain decision
packages/moss-adapter/package.json adds exactly:
@moss-mini-demo/report-schema: workspace:*;
canonicalize: 3.0.0.
The existing server-only: 0.0.1 dependency remains unchanged.
The adapter consumes only the report-schema public package entry and reuses its
accepted AssetSchema, EvmAddressSchema, ProtocolIdSchema, PositiveAmountSchema, and UnsignedAmountSchema. It does not import
report-schema private source paths and does not copy those validators.
RFC 8785 canonicalization uses the pinned canonicalize@3.0.0 implementation:
SHA-256 uses Node 22's built-in node:crypto over the canonical UTF-8 bytes.
No second hashing package is added. No hand-written or approximate JSON
canonicalizer is permitted.
pnpm-lock.yaml may add only the two adapter importer entries and the exact canonicalize@3.0.0 package record. It must not refresh unrelated versions. pnpm-workspace.yaml and the sole 'sharp@0.34.5': true build permission
remain byte-for-byte unchanged. No second build-script permission may be
created or auto-added.
5. Exact request contract
QuoteCollectionRequestV0_1 is an adapter-owned, reject-only input:
The duplicated comparison basis is intentional. Before any binding call, quoteInput.params.inputAsset, outputAsset, and amountIn must exactly
match the top-level request values. Additional protocol-neutral JSON fields in quoteInput.params are preserved and passed through, but they cannot replace
or alter the three required comparison fields.
The request is cloned once inside a sanitized input boundary. Getter, Proxy,
revoked Proxy, cyclic, non-JSON, duplicate protocol, invalid address, invalid
amount, non-143 chain, or inconsistent basis input throws a fresh MossAdapterError with code: INVALID_INPUT, operation: quote, no cause, no original message, and zero Quote delegations.
Amounts are canonical positive base-10 integer strings and must be at most 2^256 - 1. JavaScript Number, floats, exponent notation, signs,
whitespace, separators, leading zeroes, zero, and values above uint256 are
rejected. Conversion for comparison uses only BigInt.
6. Asset identity and catalog contract
QuoteAssetV0_1 is exactly the accepted report-schema asset union:
Duplicate asset identities invalidate the catalog. An absent asset produces UNKNOWN_ASSET; an explicit UNKNOWN decimals record produces UNKNOWN_DECIMALS. Both fail closed before that candidate can become
eligible. No default such as native=18 is inferred. No RPC, token contract,
symbol registry, or display metadata is consulted.
7. Exact raw Quote projection and preservation
Current RawQuote.mossOriginal.value remains the complete opaque JsonValue. #26 does not rewrite that source value or weaken its identity
boundary.
For normalization, the collector makes one adapter-owned structured clone of
the acquired raw value and extracts this required projection:
The raw top-level object may contain additional JSON fields. They remain in the
preserved raw source and owned snapshot but do not silently become normalized
fields.
Extraction reads exact named fields; it never reads a symbol or formatted
amount. Missing fields, getter/clone failures, nulls, JavaScript-number amounts,
float/exponent/negative/zero/leading-zero amounts, non-143 chain, invalid asset
shape, malformed block strings, or fromBlock > toBlock produce the fixed
per-candidate code MALFORMED_QUOTE.
Every candidate outcome is retained in byte-stable protocol order:
acquisition success and eligible: original RawQuote by identity,
deep-frozen adapter-owned raw snapshot, normalized quote, and timing evidence;
acquisition success but ineligible/malformed: original RawQuote by
identity when it can be retained, owned snapshot when created, and the fixed
structured failure;
timeout/acquisition failure: structured safe failure with no raw exception,
message, URL, header, account, params, key, or cause.
The collector never freezes, mutates, reorders, or replaces the source-owned RawQuote. Derived snapshots and normalized records are separately labelled
Mini-Demo-derived data.
ProductionMossPort, FakeMossPort, and createBoundMossPort forward
the exact signal. No other port method changes.
The collector:
creates one AbortController per allowed candidate;
starts every allowed Quote request before awaiting settlement;
fixes the deadline at exactly 8,000 milliseconds;
aborts with a stable non-sensitive timeout reason at the deadline;
records QUOTE_TIMEOUT as that candidate's terminal outcome;
attaches fulfillment and rejection handlers before racing the deadline so
every late settlement is consumed;
discards any late fulfillment/rejection after the timeout outcome is
committed;
freezes the returned derived outcome set so a late promise cannot mutate,
append, replace, or influence selection.
The aggregate uses Promise.allSettled over the complete candidate task list.
A bare Promise.race without terminal late-result handling is forbidden.
A candidate outside allowedProtocols receives PROTOCOL_NOT_ALLOWED
without invoking port.quote.
The Quote port contract for #26 is read-only and must honor AbortSignal.
Tests prove signal propagation, abort observation, late fulfillment/rejection
drainage, no unhandled rejection, no outcome mutation, and no selection
pollution. If a production binding cannot honor cancellation or cannot prove
its Quote call has no externally mutating side effect, implementation stops and
returns to Maintainer; #26 must not claim cancellation of an uncooperative
source.
10. Eligibility and deterministic selection order
Global request/catalog validation happens before any Quote delegation. For each
candidate, terminal classification uses this exact order:
canonical candidate identity and duplicate check;
allowlist membership; otherwise PROTOCOL_NOT_ALLOWED and no call;
Quote acquisition within 8 seconds; otherwise QUOTE_TIMEOUT or QUOTE_ACQUISITION_FAILED;
owned raw snapshot and complete projection validation; otherwise MALFORMED_QUOTE;
exact amountIn string equality with the request basis; otherwise AMOUNT_BASIS_MISMATCH;
catalog membership for both assets; otherwise UNKNOWN_ASSET;
KNOWN decimals with approved source metadata; otherwise UNKNOWN_DECIMALS;
lossless BigInt normalization; only then is the candidate eligible.
Because every eligible candidate must have the exact same output asset
identity, all output amounts use the same authoritative decimals. Lossless
normalization therefore does not divide, round, format, or convert display
units:
Input/output decimals records and their authority/version/provenance are
retained in NormalizedQuoteV0_1. Conflicting decimals for one asset make the
catalog invalid. Cross-asset price conversion, USD normalization, symbol-based
comparison, rounding, and Number arithmetic are forbidden.
Winner:
highest comparisonAmount wins;
exact amount tie uses protocolId UTF-8 byte lexicographic ascending;
comparison uses TextEncoder byte arrays and numeric byte comparison;
localeCompare, locale collation, case folding, Unicode normalization,
settlement order, candidate input order, wall time, and random values are
forbidden.
ProtocolId is already lowercase ASCII, so UTF-8 and ASCII bytes coincide.
Duplicate protocol IDs are rejected before collection.
All returned candidate outcomes are sorted by the same byte comparator,
independent of settlement order.
The payload is passed to canonicalize@3.0.0; the returned RFC 8785 text is
UTF-8 encoded and hashed once with Node createHash("sha256"). A
canonicalization rejection, undefined result, invalid Unicode, or non-I-JSON
value is MALFORMED_QUOTE; no fallback serializer is allowed.
The digest is a reproducibility fingerprint for the selected Quote record. It
is not a signature, Capability digest, integrity proof, execution binding, or
evidence that a later Capability came from this exact Quote.
Tests include a published RFC 8785 canonicalization vector and a fixed SHA-256
golden vector. They also recompute the selected payload digest independently
through the pinned package. No approximate property sorter is tested or used.
12. Time and block evidence
For every acquired Quote:
acquiredAt is captured when the Quote settles, using new Date(Date.now()).toISOString(), and must be canonical UTC with
milliseconds;
acquiredMonotonicNs is the canonical unsigned decimal string returned by process.hrtime.bigint();
the clock identifier is exactly NODE_PROCESS_HRTIME_V0_1;
the required observable block window comes from the validated raw projection
and uses unsigned decimal strings with fromBlock <= toBlock.
Missing or malformed block-window evidence produces MALFORMED_QUOTE; it is
never replaced with the current time or an inferred block.
acquiredAt, acquiredMonotonicNs, deadlines, and settlement order are
excluded from the RFC 8785 digest and from the selection subobject. They
cannot change eligibility, ranking, selected protocol, or digest.
#26 does not call action. It only records the monotonic acquisition token
needed for a future authorized orchestrator to compute quote-to-action elapsed
time from the same process clock. A process/clock discontinuity must be treated
as unprovable by that future scope; wall-clock subtraction is not a substitute.
13. Required tests
All data is inline and synthetic. No real protocol, token, address, Quote, RPC,
wallet, key, Receipt, simulation, or chain record is used.
packages/moss-adapter/test/quote.test.ts covers:
exact raw projection extraction;
raw identity preservation and separate frozen owned snapshot;
request/raw input and output asset validation by tagged identity, never
symbol;
exact amount-in basis matching;
integer-string/BigInt-only behavior;
zero, leading-zero, float, exponent, Number, negative, missing, and
over-uint256 rejection;
missing/invalid/reversed observable block window;
malformed Quote fixed to MALFORMED_QUOTE;
unknown asset and unknown decimals fail closed;
decimals authority, version, provenance, and reference retention;
request/getter/Proxy errors sanitized before delegation;
original request and RawQuote are not mutated;
acquired time shape and monotonic token shape;
exact RFC 8785 canonicalization vector and SHA-256 golden digest;
different wall/monotonic times produce the same normalized selection core and
selected digest.
packages/moss-adapter/test/selection.test.ts contains the complete matrix
with expected terminal outcome and selection:
both success / first has higher output -> first selected;
both success / second has higher output -> second selected;
equal output -> byte-ascending protocol selected;
reversed candidate order and reversed settlement order -> identical selection, digest, and byte-ordered outcome identities;
one timeout plus one success -> success selected and timeout retained;
late fulfillment after timeout -> timeout remains terminal and selection is
unchanged;
late rejection after timeout -> drained, no unhandled rejection or mutation;
one malformed plus one success -> success selected and malformed retained;
asset direction mismatch -> ineligible with exact code;
amount basis mismatch -> ineligible with exact code;
outside allowlist -> no delegation and exact code;
all acquisition failures -> all failures retained and NO_ELIGIBLE_QUOTE;
mixed failure classes with no eligible quote -> every class retained;
uint256 maximum values -> accepted and compared with BigInt;
unknown asset -> no eligible candidate;
unknown decimals -> no eligible candidate;
single protocol failure never removes another success;
repeated execution with controlled evidence -> identical deterministic selection and digest and no input mutation.
Cancellation regressions assert the exact AbortSignal reaches both
Production and Fake bindings. Existing five-method, source-sanitization,
input-sanitization, identity, server-only, and Fake determinism tests remain
green.
The public-entry smoke must expect exactly one additional runtime export, collectAndSelectQuotesV0_1, and must continue proving normal browser-like
import failure through the existing server-only guard.
14. Implementation sequence after authorization
Re-fetch and verify exact main. Stop if it is not a0f3a3e8605812c9f0997059b4a30ea7a736022c.
Create only the proposed branch and isolated worktree.
Add the exact report-schema workspace dependency and canonicalize@3.0.0; update only the allowed lockfile records.
Add the versioned type contracts and AbortSignal forwarding while preserving
the five-method MossPort.
Implement reject-only asset catalog validation.
Implement raw Quote projection, source/derived separation, timeout/abort and
complete per-protocol outcome collection with Promise.allSettled.
Implement byte-stable selection and the fixed RFC8785/SHA-256 digest.
Add the two focused test files and update only the listed regressions/smoke.
Audit exact paths, dependency integrity, late-promise behavior, public
exports, and prohibited wording.
Run clean-checkout verification, push one Draft PR with Closes #26,
wait for exact-head CI, and hand the frozen head to independent Pre-PR QA.
No implementation starts before an explicit SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED comment accepts this plan,
including the optional AbortSignal interface expansion and the two dependencies.
15. Verification and CI acceptance
Use Node 22.23.1 and pnpm 11.16.0. Final verification runs from a fresh
isolated checkout with no pre-existing dist or .next:
No ADR, workflow, documentation, report-schema source, decision-engine,
Fixture, Issue/Project state, branch protection, required check, permission, or
main change is in scope.
digesting timestamps and making selection nondeterministic;
exposing raw source errors or secrets;
accidental claims that selection is best, safe, or bound to Capability.
Stop and return to Maintainer if:
main differs before branch creation;
AbortSignal cannot be propagated and honored;
a source operation may mutate external state after timeout;
a real protocol/address/catalog decision is required;
a third dependency, build-script permission, public runtime export, root
script, or seventeenth path is needed;
canonicalize package identity/integrity differs;
raw Quote cannot provide the fixed projection or block window;
digest reproducibility fails an RFC/golden vector;
any implementation would cross into Capability, simulation, Alignment,
Decision, Web/API, RPC, wallet, signing, or transaction behavior.
Rollback is one revert of the #26 implementation commit after merge, or removal
of only the unmerged #26 branch/PR. It must not revert #25/#24, alter main
directly, change the Moss gitlink, or modify protection/required checks.
18. Requested Maintainer decision
Please record one of:
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED, explicitly accepting the
exact 16 paths, the two dependencies, the optional AbortSignal expansion,
the raw Quote projection, asset catalog contract, timeout behavior,
selection law, digest payload, and time exclusion; or
SCOPE_CHANGES_REQUESTED, naming the exact path, dependency, API, evidence,
or semantic decision that must change.
canonicalize@3.0.0 metadata was independently verified: Apache-2.0, zero runtime dependencies, built-in type declaration, no install/build lifecycle script, and the stated registry integrity matches.
1. Asset-catalog authority is currently self-asserted
assetCatalog is part of the same public, caller-controlled QuoteCollectionRequestV0_1, yet an entry may declare authority: "MAINTAINER_APPROVED" and provenance: "CONFIGURATION". Input cloning and shape validation cannot prove those claims. A caller can construct arbitrary decimals/source metadata and thereby make a candidate eligible under a false authority label.
The revised plan must define a real trust boundary:
separate untrusted quote request data from server-owned catalog configuration, or remove the MAINTAINER_APPROVED claim and define the weaker caller-supplied semantics;
identify the catalog owner and exact injection/loading boundary;
define catalog-level identity/version/provenance and whether a digest or immutable source record is required;
give exact grammar and length for sourceVersion and sourceReference rather than “bounded ASCII”;
specify fail-closed behavior when trusted catalog configuration is absent, unknown, duplicated, stale or inconsistent;
make clear that synthetic test catalogs are not production/Maintainer-approved asset evidence.
No real address needs to be added by #26, but arbitrary request data must not be able to self-certify authority.
2. Public result and candidate unions are not exact enough
The plan names the exported types but does not freeze the complete shape of QuoteCandidateOutcomeV0_1, the selected top-level result, normalized records, timing records, failure records or source-error retention. The prose leaves Builder decisions about discriminants, optional fields and field ownership.
The revised plan must provide exact TypeScript-like discriminated shapes for:
acquired eligible success;
acquired but ineligible/malformed outcome;
timeout/acquisition failure;
selected and NOT_SELECTED top-level results;
exact placement of raw identity, owned snapshot, normalized data, timing evidence, failure code and optional sourceErrorCode;
exact immutability and candidate ordering rules.
Each candidate must have exactly one terminal discriminant and one failure precedence outcome. No optional-field combination may imply contradictory success/failure states.
3. Timeout must not overclaim source cancellation
The collector-local 8,000 ms terminal timeout and late-promise drainage are sound, but the plan also says the production Quote binding “must honor” AbortSignal. #25 provides an injected structural binding and this repository has no real protocol binding whose cancellation behavior can be proven in #26. Signal forwarding is testable; actual source cancellation is not guaranteed by the TypeScript interface.
Revise the contract to distinguish:
collector terminality: exactly when QUOTE_TIMEOUT becomes immutable;
signal propagation: exact abort reason/value and when abort() is called;
underlying-source cancellation: never claimed unless a concrete binding proves it;
an uncooperative source that ignores the signal and fulfills/rejects late: must be drained, must not mutate outcomes or selection, and must not produce an unhandled rejection;
Add explicit cooperative and signal-ignoring late-fulfillment/late-rejection matrix cases.
4. RFC 8785 evidence must be frozen to exact vectors
The dependency and hashing direction are acceptable. The revised plan must identify the exact published RFC 8785 test vector(s), expected canonical UTF-8 text/bytes, and the exact fixed payload plus expected lowercase SHA-256 value used as the golden test. “A published vector” still leaves the implementation to invent the actual acceptance evidence.
Required resubmission
Leave this Work Plan unchanged as history and submit one complete revised Work Plan comment. Reconfirm the same main baseline, or refresh the entire plan if main moves. The revision must restate the full path list, dependencies, port change, exact public contracts, catalog authority, timeout semantics, digest/time rules, tests, non-goals and stop conditions.
#26 remains Open / Qy assigned / Project In Progress for planning only. This comment is not implementation authorization. #23 remains Ready/unassigned; #27 and later dependent issues remain Blocked.
Final Implementation Work Plan v2 - M2-05 Quote Collection and Deterministic Selection - Awaiting Maintainer Scope Confirmation
0. Status, history, authority, and exact baseline
This is a complete, self-contained replacement proposal for the #26
implementation scope. It supersedes the prior Work Plan for future Scope Gate
purposes, but does not edit or delete history.
proposed branch only after Scope Confirmation: codex/issue-26-quote-selection
proposed isolated worktree only after authorization: /Users/qy/Documents/moss-mini-demo-issue-26
This comment is planning only. It is not SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED, QA PASS, Review,
READY_TO_MERGE, Merge Gate, or merge authorization. No branch, worktree,
repository file, dependency, lockfile, commit, push, or PR is created by this
comment.
If origin/main changes before branch creation, Builder stops, rescans the
new main, and requests a new Scope Gate instead of implementing against this
baseline.
1. Goal and trust boundary
Add one server-only, deterministic Quote collection and candidate-selection
operation to the existing @moss-mini-demo/moss-adapter public entry.
The operation:
receives untrusted request data separately from server-owned asset catalog
configuration;
validates chain-143 comparison basis and catalog freshness/integrity;
records exactly one terminal outcome for every candidate;
preserves every acquired RawQuote separately from Mini-Demo-derived
snapshots and normalization;
selects only among eligible normalized outcomes using the disclosed rule;
returns either one selected candidate or an explicit no-eligible-candidate
result.
A Quote is protocol-selection context only. It is not Capability, simulation,
execution evidence, a best-trade claim, safety, approval, authorization, or a
cryptographic binding to a later Capability.
The only public rule identifier is:
DETERMINISTIC_CANDIDATE_SELECTION_V0_1
Public output and tests must not call the result best, optimal, safe, approved,
executable, guaranteed, or equivalent.
2. Exact 16-path writable list
Implementation may modify exactly these 16 repository paths and no others:
No public canonicalization helper, hash helper, comparator, catalog factory,
asset lookup helper, timer helper, second port, runtime Schema, or
source-binding bypass is added.
4. Exact dependencies and supply-chain policy
packages/moss-adapter/package.json adds exactly:
@moss-mini-demo/report-schema: workspace:*;
canonicalize: 3.0.0.
The existing server-only: 0.0.1 dependency remains unchanged.
The adapter consumes only the report-schema public package entry and reuses:
AssetSchema;
EvmAddressSchema;
ProtocolIdSchema;
PositiveAmountSchema;
UnsignedAmountSchema.
It does not import report-schema private source or copy those validators.
SHA-256 uses Node 22 node:crypto over canonical UTF-8 bytes. No second hash
dependency and no hand-written/approximate canonicalizer is allowed.
The lockfile may add only:
@moss-mini-demo/report-schema: workspace:* to the moss-adapter importer;
canonicalize: 3.0.0 to that importer;
the exact canonicalize@3.0.0 package/snapshot record.
No unrelated version refresh is accepted. pnpm-workspace.yaml and the sole 'sharp@0.34.5': true build permission remain byte-for-byte unchanged. No
second build-script permission may be added manually or by pnpm.
5. Untrusted request contract
QuoteCollectionRequestV0_1 is reject-only caller data:
each ProtocolId uses the accepted lowercase ASCII kebab grammar;
each array is unique; no trimming, sorting-as-repair, case folding, or
deduplication occurs;
chainId is exactly 143;
account is an exact EIP-55 non-zero address;
quoteInput.params.inputAsset, outputAsset, and amountIn exactly
equal the top-level basis;
additional params remain JSON only and cannot replace the required fields.
The request is cloned once inside a sanitized boundary. Getter, hostile/revoked
Proxy, cyclic/non-JSON input, duplicate protocol, invalid address, invalid
amount, wrong chain, or inconsistent duplicated basis throws a new MossAdapterError:
Amounts are canonical positive base-10 integer strings no larger than 2^256 - 1. Number, float, exponent, sign, whitespace, separator, leading
zero, zero, and over-uint256 forms are rejected. Ranking conversion uses only BigInt.
6. Asset identity and server-owned catalog boundary
symbol/name/icon/ticker/decimals do not establish identity;
no lowercasing, checksum repair, symbol lookup, address inference, or native
sentinel occurs.
The catalog is not inside QuoteCollectionRequestV0_1. It is injected
separately by the server composition owner. #26 provides no loader and commits
no production catalog/address. A later Web/API composition scope owns loading
and access control.
The catalog never claims MAINTAINER_APPROVED. Its provenance is only a
source-channel classification and does not prove approval, correctness, or live
evidence:
timestamps: calendar-valid canonical UTC with exactly millisecond precision, YYYY-MM-DDTHH:mm:ss.sssZ;
validFrom < validUntil;
freshness at collection start is validFrom <= new Date(Date.now()) < validUntil;
known decimals are safe integers 0..255;
entries are non-empty and asset identities are unique.
Catalog validation happens before any Quote call. Missing catalog, getter/Proxy,
wrong schema/chain, malformed source metadata, empty/duplicate entries,
conflicting duplicate decimals, invalid time interval, not-yet-valid catalog,
expired catalog, or clone/freeze failure throws the same stable INVALID_INPUT / quote error with zero delegations.
A structurally valid catalog may intentionally omit an asset or record UNKNOWN decimals:
requested asset absent -> every otherwise allowed candidate is SKIPPED
with UNKNOWN_ASSET, zero Quote calls;
requested asset decimals UNKNOWN -> every otherwise allowed candidate is SKIPPED with UNKNOWN_DECIMALS, zero Quote calls.
Synthetic tests must use provenance: "SYNTHETIC_TEST". Such a catalog is
test configuration only, not production/Maintainer-approved asset evidence. SERVER_CONFIGURED likewise identifies loading channel only and is not an
approval claim.
7. Catalog immutable snapshot and digest
After validation, the adapter:
creates an owned clone;
sorts entries by canonical asset-key UTF-8 bytes: ERC20:<EIP55 address> or NATIVE;
The digest proves only deterministic content identity of the owned catalog
snapshot. It does not authenticate who supplied it and is not approval or
chain evidence.
The catalog snapshot is included once in the top-level result. Normalized
quotes reference its identity/digest rather than copying authority claims.
8. Raw Quote projection and source/derived separation
Current RawQuote.mossOriginal.value remains complete opaque JsonValue. #26 does not rewrite, freeze, or replace it.
The collector takes one adapter-owned structured clone and extracts:
Only MALFORMED_QUOTE may carry UNSNAPSHOTTABLE. Every other acquired
outcome has SNAPSHOTTED.
The adapter never mutates or freezes source. Containers, snapshots,
catalog, normalized data, timing data, failures, digest payload, outcome array,
and result are frozen. Freezing a derived container must not recursively freeze
the source-owned RawQuote; implementation freezes owned fields explicitly.
each candidate gets exactly one terminal timing record;
acquired candidates name it acquiredTiming;
skipped/acquisition-failed candidates name it terminalTiming.
Timing is observation metadata. It is excluded from ranking, selected digest,
catalog digest, and deterministic selection fields.
#26 does not call action. The monotonic acquisition token only allows a
future authorized same-process orchestrator to calculate quote-to-action
elapsed time. Clock/process discontinuity is unprovable; wall-clock subtraction
must not replace the monotonic calculation.
Global invalid request/catalog throws MossAdapterError(INVALID_INPUT, quote)
before candidate outcomes exist.
Per-candidate precedence is exactly:
outside allowed set -> PROTOCOL_NOT_ALLOWED;
requested asset absent -> UNKNOWN_ASSET;
requested decimals unknown -> UNKNOWN_DECIMALS;
8,000 ms collector deadline -> QUOTE_TIMEOUT;
source reject/throw before deadline -> QUOTE_ACQUISITION_FAILED;
raw snapshot/projection/canonicalization invalid -> MALFORMED_QUOTE;
raw input/output asset differs -> ASSET_DIRECTION_MISMATCH;
raw amountIn differs -> AMOUNT_BASIS_MISMATCH;
otherwise -> ELIGIBLE.
Exactly one precedence result is retained per candidate. Later checks do not
overwrite an earlier failure.
An existing stable source MossAdapterError.code is retained only in the QUOTE_ACQUISITION_FAILED branch as sourceErrorCode: MossAdapterErrorCode | null. Generic/hostile exceptions
produce null. No raw exception, cause, message, URL, headers, account,
params, key, or source object is retained in that branch.
No division, multiplication, rounding, display unit, cross-asset conversion,
USD value, symbol, or Number is used. The maximum uint256 value is accepted.
Winner:
highest BigInt(normalizedAmountOut);
tie -> ProtocolId UTF-8 byte lexicographic ascending;
comparator uses TextEncoder and numeric byte comparison;
no localeCompare, collation, case folding, Unicode normalization,
candidate order, settlement order, time, random value, or environment input.
ProtocolId is canonical lowercase ASCII, so its UTF-8 and ASCII bytes coincide.
13. Port change and exact timeout semantics
This v2 still requests a new Scope Gate for the disclosed, backward-compatible
optional signal expansion:
#26 does not claim that the underlying source request was canceled. A
cooperative source may stop. A signal-ignoring source may still fulfill/reject
later; both paths are drained. Quote is required to be a read-only operation,
but this interface cannot prove absence of external effects in an unimplemented
real source.
No output or documentation may say “source canceled” or equivalent unless a
future concrete binding independently proves that behavior.
A bare Promise.race without preattached late-settlement drainage is
forbidden.
14. Exact selected digest and top-level result unions
SELECTED exists only when exactly one outcome is the deterministic winner.
The selected protocol references an ELIGIBLE outcome. NOT_SELECTED
exists only when zero outcomes are eligible. The full candidate list is always
present.
It is passed to canonicalize@3.0.0; canonical UTF-8 bytes are hashed once
with Node createHash("sha256"). Output is sha256: plus exactly 64 lowercase hex characters.
A canonicalization rejection, undefined result, invalid Unicode, or non-I-JSON
value yields MALFORMED_QUOTE; no fallback serializer exists.
The digest is only a deterministic fingerprint of selected Quote context. It
is not a signature, Capability digest, integrity proof, execution binding, or
evidence that a later Capability came from this Quote.
acquiredTiming, terminalTiming, candidate order, settlement order,
deadline, and wall/monotonic time are excluded from catalog digest, selected
digest, ranking, and selected subobject.
15. Frozen RFC 8785 conformance vector
The implementation test must use the exact public values.json vector from
the RFC 8785 reference test corpus:
Tests must compare the fixed payload, canonical text, and expected hash
literally. Recomputing expected values using the code under test is not
acceptance evidence.
All addresses, protocol IDs, times, amounts, block values, raw values, catalog
metadata, and provenance in these vectors are synthetic test data.
17. Complete deterministic selection and timeout test matrix
packages/moss-adapter/test/quote.test.ts must cover:
exact request clone/reject boundary;
catalog separate from request and no self-approved authority field;
catalog grammar, clone, sort, freeze, freshness, digest, and non-mutation;
missing, duplicate, inconsistent, not-yet-valid, and stale catalog -> stable
INVALID_INPUT and zero delegations;
exact dependency/lockfile change and no build-policy change;
frozen install independent of historic artifacts;
focused, adapter, package-import, full, browser-bundle, and production tests
pass;
all fixed canonical text/byte/hash vectors pass literally;
all candidate branches and precedence rules pass;
no Number amount path, locale comparator, time-dependent selection, raw
mutation, late-promise mutation, unhandled rejection, or source-cancellation
overclaim;
existing workflow unchanged and exact pushed-head quality-gate SUCCESS;
a source operation is not read-only and timeout behavior could create
external mutation;
signal forwarding requires a sixth port method or required breaking
parameter;
any third dependency, build permission, runtime export, root script,
seventeenth path, workflow, docs, ADR, Schema, Web/API, or vendor change is
needed;
canonicalize identity/integrity differs;
fixed RFC/catalog/selected vectors do not reproduce exactly;
raw Quote cannot supply the fixed projection/block window;
implementation crosses into Capability, simulation, Alignment, Decision,
RPC, wallet, signing, or transaction behavior.
Rollback is one revert of the #26 implementation commit after merge, or removal
of only the unmerged #26 branch/PR. It must not revert #25/#24, edit main
directly, change the Moss gitlink, or modify protection/required checks.
22. Requested Maintainer decision
Please record one of:
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED, explicitly accepting this v2
comment, exact 16 paths, two dependencies, public API/unions, separate
catalog trust semantics, catalog digest/freshness, optional signal forwarding,
collector-only timeout claims, raw/normalized ownership, deterministic
selection, exact vectors, non-goals, and stop conditions; or
SCOPE_CHANGES_REQUESTED, naming the exact path, dependency, API, trust,
evidence, vector, or semantic decision that must change.
Because RawQuoteRetentionV0_1 includes status: "UNSNAPSHOTTABLE", the actual exported type accepts both contradictory combinations:
UNSNAPSHOTTABLE + ASSET_DIRECTION_MISMATCH;
UNSNAPSHOTTABLE + AMOUNT_BASIS_MISMATCH.
The following prose says implementation will refine this, but prose does not change the public TypeScript contract. The type itself must make invalid combinations unrepresentable. Define exact correlated branches, for example:
MALFORMED_QUOTE with RawQuoteRetentionV0_1;
ASSET_DIRECTION_MISMATCH with SNAPSHOTTED only;
AMOUNT_BASIS_MISMATCH with SNAPSHOTTED only.
Freeze the literal exported union in the revised plan and add compile-time/type-level plus runtime matrix evidence for the forbidden combinations.
2. RFC 8785 canonical text contradicts its bytes and SHA
Section 15 labels this exact text as canonical:
..."string":"EUR-CONTROL-CHAR-RENDERING"...
The actual v2 block renders the U+000F position as backslash-caret-O (5c 5e 4f). Backslash-caret is not a valid JSON escape. The declared canonical byte vector instead encodes 5c 75 30 30 30 66 (the six ASCII bytes for a lowercase Unicode escape of U+000F).
Independent calculation gives:
SHA-256 of the exact canonical-text block currently printed in v2: c92e902800898ec717a3dd3bee5eb3f256f3ca1b18810feb9cc45759a376fe01;
SHA-256 of the declared byte vector: 2d5e01a318d0f0879ab568c4be289c8b1f64ef8921a53c6277d5e069978baacb.
The declared byte vector and second hash agree with the RFC 8785 reference vector; the printed canonical text does not. Replace it with exact valid canonical JSON using the lowercase six-character Unicode escape for U+000F, then independently prove all three representations are identical:
canonical text UTF-8 encoding equals the frozen hex bytes;
those bytes hash to the frozen SHA;
canonicalize@3.0.0 output equals the same text.
Do not retain two competing golden representations.
Required resubmission
Keep v1 and v2 unchanged as audit history. Submit one complete, self-contained Work Plan v3 with the exact correlated public union and corrected RFC vector reproduced throughout. Reconfirm the baseline and restate all 16 paths, two dependencies, catalog boundary, timeout semantics, full public shapes, vectors, tests, non-goals and stop conditions.
#26 remains Open / Qy assigned / Project In Progress for planning only. #23 remains Ready/unassigned; #27 and later dependent Issues remain Blocked. Scope authorization and local environment cleanup remain deferred.
Final Implementation Work Plan v3 - M2-05 Quote Collection and Deterministic Selection - Awaiting Maintainer Scope Confirmation
0. Status, history, authority, and exact baseline
This is a complete, self-contained replacement proposal for the #26
implementation scope. It supersedes the prior Work Plan for future Scope Gate
purposes, but does not edit or delete history.
This v3 is a full replacement proposal for the future Scope Gate. It does not
edit or delete v1, v2, or either review comment.
All boundaries accepted during the v2 review remain unchanged: the catalog is
separate from untrusted request data; catalog provenance is not Maintainer
approval; failure precedence is singular; timeout proves collector terminality
and signal propagation only; late fulfillment/rejection is drained; BigInt,
timing exclusion, raw ownership, Quote-not-execution-evidence language, the
exact 16 paths, and the exact two dependencies remain fixed.
The two remaining v2 blockers are corrected throughout this complete plan:
the exported QuoteCandidateOutcomeV0_1 now contains three separately
correlated INELIGIBLE branches, making UNSNAPSHOTTABLE + ASSET_DIRECTION_MISMATCH and UNSNAPSHOTTABLE + AMOUNT_BASIS_MISMATCH unrepresentable;
the RFC 8785 canonical text now contains the literal six ASCII characters \u000f, and the plan freezes one canonical text whose UTF-8 bytes, byte
vector, SHA-256, and canonicalize@3.0.0 output must all be identical.
Exact planning baseline was rechecked immediately before this comment:
proposed branch only after Scope Confirmation: codex/issue-26-quote-selection
proposed isolated worktree only after authorization: /Users/qy/Documents/moss-mini-demo-issue-26
This comment is planning only. It is not SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED, QA PASS, Review,
READY_TO_MERGE, Merge Gate, or merge authorization. No branch, worktree,
repository file, dependency, lockfile, commit, push, or PR is created by this
comment.
If origin/main changes before branch creation, Builder stops, rescans the
new main, and requests a new Scope Gate instead of implementing against this
baseline.
1. Goal and trust boundary
Add one server-only, deterministic Quote collection and candidate-selection
operation to the existing @moss-mini-demo/moss-adapter public entry.
The operation:
receives untrusted request data separately from server-owned asset catalog
configuration;
validates chain-143 comparison basis and catalog freshness/integrity;
records exactly one terminal outcome for every candidate;
preserves every acquired RawQuote separately from Mini-Demo-derived
snapshots and normalization;
selects only among eligible normalized outcomes using the disclosed rule;
returns either one selected candidate or an explicit no-eligible-candidate
result.
A Quote is protocol-selection context only. It is not Capability, simulation,
execution evidence, a best-trade claim, safety, approval, authorization, or a
cryptographic binding to a later Capability.
The only public rule identifier is:
DETERMINISTIC_CANDIDATE_SELECTION_V0_1
Public output and tests must not call the result best, optimal, safe, approved,
executable, guaranteed, or equivalent.
2. Exact 16-path writable list
Implementation may modify exactly these 16 repository paths and no others:
No public canonicalization helper, hash helper, comparator, catalog factory,
asset lookup helper, timer helper, second port, runtime Schema, or
source-binding bypass is added.
4. Exact dependencies and supply-chain policy
packages/moss-adapter/package.json adds exactly:
@moss-mini-demo/report-schema: workspace:*;
canonicalize: 3.0.0.
The existing server-only: 0.0.1 dependency remains unchanged.
The adapter consumes only the report-schema public package entry and reuses:
AssetSchema;
EvmAddressSchema;
ProtocolIdSchema;
PositiveAmountSchema;
UnsignedAmountSchema.
It does not import report-schema private source or copy those validators.
SHA-256 uses Node 22 node:crypto over canonical UTF-8 bytes. No second hash
dependency and no hand-written/approximate canonicalizer is allowed.
The lockfile may add only:
@moss-mini-demo/report-schema: workspace:* to the moss-adapter importer;
canonicalize: 3.0.0 to that importer;
the exact canonicalize@3.0.0 package/snapshot record.
No unrelated version refresh is accepted. pnpm-workspace.yaml and the sole 'sharp@0.34.5': true build permission remain byte-for-byte unchanged. No
second build-script permission may be added manually or by pnpm.
5. Untrusted request contract
QuoteCollectionRequestV0_1 is reject-only caller data:
each ProtocolId uses the accepted lowercase ASCII kebab grammar;
each array is unique; no trimming, sorting-as-repair, case folding, or
deduplication occurs;
chainId is exactly 143;
account is an exact EIP-55 non-zero address;
quoteInput.params.inputAsset, outputAsset, and amountIn exactly
equal the top-level basis;
additional params remain JSON only and cannot replace the required fields.
The request is cloned once inside a sanitized boundary. Getter, hostile/revoked
Proxy, cyclic/non-JSON input, duplicate protocol, invalid address, invalid
amount, wrong chain, or inconsistent duplicated basis throws a new MossAdapterError:
Amounts are canonical positive base-10 integer strings no larger than 2^256 - 1. Number, float, exponent, sign, whitespace, separator, leading
zero, zero, and over-uint256 forms are rejected. Ranking conversion uses only BigInt.
6. Asset identity and server-owned catalog boundary
symbol/name/icon/ticker/decimals do not establish identity;
no lowercasing, checksum repair, symbol lookup, address inference, or native
sentinel occurs.
The catalog is not inside QuoteCollectionRequestV0_1. It is injected
separately by the server composition owner. #26 provides no loader and commits
no production catalog/address. A later Web/API composition scope owns loading
and access control.
The catalog never claims MAINTAINER_APPROVED. Its provenance is only a
source-channel classification and does not prove approval, correctness, or live
evidence:
timestamps: calendar-valid canonical UTC with exactly millisecond precision, YYYY-MM-DDTHH:mm:ss.sssZ;
validFrom < validUntil;
freshness at collection start is validFrom <= new Date(Date.now()) < validUntil;
known decimals are safe integers 0..255;
entries are non-empty and asset identities are unique.
Catalog validation happens before any Quote call. Missing catalog, getter/Proxy,
wrong schema/chain, malformed source metadata, empty/duplicate entries,
conflicting duplicate decimals, invalid time interval, not-yet-valid catalog,
expired catalog, or clone/freeze failure throws the same stable INVALID_INPUT / quote error with zero delegations.
A structurally valid catalog may intentionally omit an asset or record UNKNOWN decimals:
requested asset absent -> every otherwise allowed candidate is SKIPPED
with UNKNOWN_ASSET, zero Quote calls;
requested asset decimals UNKNOWN -> every otherwise allowed candidate is SKIPPED with UNKNOWN_DECIMALS, zero Quote calls.
Synthetic tests must use provenance: "SYNTHETIC_TEST". Such a catalog is
test configuration only, not production/Maintainer-approved asset evidence. SERVER_CONFIGURED likewise identifies loading channel only and is not an
approval claim.
7. Catalog immutable snapshot and digest
After validation, the adapter:
creates an owned clone;
sorts entries by canonical asset-key UTF-8 bytes: ERC20:<EIP55 address> or NATIVE;
The digest proves only deterministic content identity of the owned catalog
snapshot. It does not authenticate who supplied it and is not approval or
chain evidence.
The catalog snapshot is included once in the top-level result. Normalized
quotes reference its identity/digest rather than copying authority claims.
8. Raw Quote projection and source/derived separation
Current RawQuote.mossOriginal.value remains complete opaque JsonValue. #26 does not rewrite, freeze, or replace it.
The collector takes one adapter-owned structured clone and extracts:
Only MALFORMED_QUOTE may carry UNSNAPSHOTTABLE. Every other acquired
outcome has SNAPSHOTTED.
The adapter never mutates or freezes source. Containers, snapshots,
catalog, normalized data, timing data, failures, digest payload, outcome array,
and result are frozen. Freezing a derived container must not recursively freeze
the source-owned RawQuote; implementation freezes owned fields explicitly.
each candidate gets exactly one terminal timing record;
acquired candidates name it acquiredTiming;
skipped/acquisition-failed candidates name it terminalTiming.
Timing is observation metadata. It is excluded from ranking, selected digest,
catalog digest, and deterministic selection fields.
#26 does not call action. The monotonic acquisition token only allows a
future authorized same-process orchestrator to calculate quote-to-action
elapsed time. Clock/process discontinuity is unprovable; wall-clock subtraction
must not replace the monotonic calculation.
Global invalid request/catalog throws MossAdapterError(INVALID_INPUT, quote)
before candidate outcomes exist.
Per-candidate precedence is exactly:
outside allowed set -> PROTOCOL_NOT_ALLOWED;
requested asset absent -> UNKNOWN_ASSET;
requested decimals unknown -> UNKNOWN_DECIMALS;
8,000 ms collector deadline -> QUOTE_TIMEOUT;
source reject/throw before deadline -> QUOTE_ACQUISITION_FAILED;
raw snapshot/projection/canonicalization invalid -> MALFORMED_QUOTE;
raw input/output asset differs -> ASSET_DIRECTION_MISMATCH;
raw amountIn differs -> AMOUNT_BASIS_MISMATCH;
otherwise -> ELIGIBLE.
Exactly one precedence result is retained per candidate. Later checks do not
overwrite an earlier failure.
An existing stable source MossAdapterError.code is retained only in the QUOTE_ACQUISITION_FAILED branch as sourceErrorCode: MossAdapterErrorCode | null. Generic/hostile exceptions
produce null. No raw exception, cause, message, URL, headers, account,
params, key, or source object is retained in that branch.
11. Exact correlated candidate outcome discriminated union
QuoteCandidateOutcomeV0_1 is exported exactly as the following literal
union. The three INELIGIBLE variants are separate union members; raw and failure are not independent unions.
Correlation is therefore part of the exported TypeScript contract:
MALFORMED_QUOTE may pair with either SNAPSHOTTED or UNSNAPSHOTTABLE from RawQuoteRetentionV0_1;
ASSET_DIRECTION_MISMATCH can pair only with SNAPSHOTTED;
AMOUNT_BASIS_MISMATCH can pair only with SNAPSHOTTED;
ELIGIBLE can pair only with SNAPSHOTTED and must contain normalized;
no branch has optional raw, timing, normalized, or failure fields.
packages/moss-adapter/test/contracts.test.ts must freeze compile-time evidence:
valid examples for both malformed raw-retention variants and both
snapshotted mismatch variants use satisfies QuoteCandidateOutcomeV0_1;
Extract plus an AssertNever<T extends never> assertion proves each UNSNAPSHOTTABLE mismatch intersection is never;
literal assignments for UNSNAPSHOTTABLE + ASSET_DIRECTION_MISMATCH and UNSNAPSHOTTABLE + AMOUNT_BASIS_MISMATCH are each guarded by @ts-expect-error, and typecheck fails if either directive becomes unused.
Runtime collector tests separately exercise malformed-snapshotted,
malformed-unsnapshottable, asset-mismatch-snapshotted, and
amount-mismatch-snapshotted outcomes and assert their exact keys. They also
assert that no produced asset/amount mismatch has raw.status === "UNSNAPSHOTTABLE".
Every candidate ProtocolId appears once. Outcomes are sorted by ProtocolId
UTF-8 byte order, not input or settlement order.
12. Normalized quote contract and lossless ranking
No division, multiplication, rounding, display unit, cross-asset conversion,
USD value, symbol, or Number is used. The maximum uint256 value is accepted.
Winner:
highest BigInt(normalizedAmountOut);
tie -> ProtocolId UTF-8 byte lexicographic ascending;
comparator uses TextEncoder and numeric byte comparison;
no localeCompare, collation, case folding, Unicode normalization,
candidate order, settlement order, time, random value, or environment input.
ProtocolId is canonical lowercase ASCII, so its UTF-8 and ASCII bytes coincide.
13. Port change and exact timeout semantics
This v3 still requests a new Scope Gate for the disclosed, backward-compatible
optional signal expansion:
#26 does not claim that the underlying source request was canceled. A
cooperative source may stop. A signal-ignoring source may still fulfill/reject
later; both paths are drained. Quote is required to be a read-only operation,
but this interface cannot prove absence of external effects in an unimplemented
real source.
No output or documentation may say “source canceled” or equivalent unless a
future concrete binding independently proves that behavior.
A bare Promise.race without preattached late-settlement drainage is
forbidden.
14. Exact selected digest and top-level result unions
SELECTED exists only when exactly one outcome is the deterministic winner.
The selected protocol references an ELIGIBLE outcome. NOT_SELECTED
exists only when zero outcomes are eligible. The full candidate list is always
present.
It is passed to canonicalize@3.0.0; canonical UTF-8 bytes are hashed once
with Node createHash("sha256"). Output is sha256: plus exactly 64 lowercase hex characters.
A canonicalization rejection, undefined result, invalid Unicode, or non-I-JSON
value yields MALFORMED_QUOTE; no fallback serializer exists.
The digest is only a deterministic fingerprint of selected Quote context. It
is not a signature, Capability digest, integrity proof, execution binding, or
evidence that a later Capability came from this Quote.
acquiredTiming, terminalTiming, candidate order, settlement order,
deadline, and wall/monotonic time are excluded from catalog digest, selected
digest, ranking, and selected subobject.
15. Frozen RFC 8785 conformance vector with one canonical representation
The implementation test uses the exact public values.json vector from the
RFC 8785 reference test corpus:
The single exact canonical text is the following valid JSON. The U+000F
position is represented by the literal six ASCII characters \u000f;
there is no caret notation and no second text representation.
The expected text, bytes, and SHA are literal constants taken from the
reference corpus and independently frozen in the test. Expected values must
not be regenerated from the implementation under test. There is no fallback
serializer and no competing golden representation.
16. Frozen synthetic catalog and selected-Quote golden vectors
Tests must compare the fixed payload, canonical text, and expected hash
literally. Recomputing expected values using the code under test is not
acceptance evidence.
All addresses, protocol IDs, times, amounts, block values, raw values, catalog
metadata, and provenance in these vectors are synthetic test data.
17. Complete deterministic selection and timeout test matrix
packages/moss-adapter/test/quote.test.ts must cover:
exact request clone/reject boundary;
catalog separate from request and no self-approved authority field;
catalog grammar, clone, sort, freeze, freshness, digest, and non-mutation;
missing, duplicate, inconsistent, not-yet-valid, and stale catalog -> stable
INVALID_INPUT and zero delegations;
exact dependency/lockfile change and no build-policy change;
frozen install independent of historic artifacts;
focused, adapter, package-import, full, browser-bundle, and production tests
pass;
all fixed canonical text/byte/hash vectors pass literally;
RFC canonical text parses, encodes to the frozen bytes, hashes to the frozen
SHA, and equals canonicalize@3.0.0 output;
correlated compile-time/type-level and runtime outcome matrices pass;
all candidate branches and precedence rules pass;
no Number amount path, locale comparator, time-dependent selection, raw
mutation, late-promise mutation, unhandled rejection, or source-cancellation
overclaim;
existing workflow unchanged and exact pushed-head quality-gate SUCCESS;
a source operation is not read-only and timeout behavior could create
external mutation;
signal forwarding requires a sixth port method or required breaking
parameter;
any third dependency, build permission, runtime export, root script,
seventeenth path, workflow, docs, ADR, Schema, Web/API, or vendor change is
needed;
canonicalize identity/integrity differs;
fixed RFC/catalog/selected vectors do not reproduce exactly;
raw Quote cannot supply the fixed projection/block window;
implementation crosses into Capability, simulation, Alignment, Decision,
RPC, wallet, signing, or transaction behavior.
Rollback is one revert of the #26 implementation commit after merge, or removal
of only the unmerged #26 branch/PR. It must not revert #25/#24, edit main
directly, change the Moss gitlink, or modify protection/required checks.
22. Requested Maintainer decision
Please record one of:
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED, explicitly accepting this v3
comment, exact 16 paths, two dependencies, public API/unions, separate
catalog trust semantics, catalog digest/freshness, optional signal forwarding,
collector-only timeout claims, raw/normalized ownership, deterministic
selection, exact vectors, non-goals, and stop conditions; or
SCOPE_CHANGES_REQUESTED, naming the exact path, dependency, API, trust,
evidence, vector, or semantic decision that must change.
The v2 correlated-union blocker is resolved at plan level. The exported union has separate malformed, asset-mismatch, and amount-mismatch members; both forbidden UNSNAPSHOTTABLE mismatch combinations are unrepresentable. The proposed compile-time satisfies / AssertNever / @ts-expect-error checks and the runtime correlation matrix are adequate. The previously accepted catalog authority, timeout and late-drainage, BigInt, digest, raw-evidence, and Quote-not-execution-evidence boundaries remain intact. The scope remains exactly 16 paths and two dependencies, with no #27 behavior.
One P0 vector blocker remains in Sections 0 and 15:
The reference input and expected canonical JSON encode the U+000F position as backslash-caret-O (hex 5c 5e 4f), not the required six-byte JSON escape: backslash, lowercase u, and four hex digits 000f (hex 5c 75 30 30 30 66).
JSON.parse(referenceInputText) fails at line 3 column 22 with a bad escaped character.
JSON.parse(expectedCanonicalText) fails at line 1 column 96 with a bad escaped character.
The actual expected-text bytes are 115 bytes and contain hex 5c5e4f; the declared vector is 118 bytes and contains 5c7530303066.
SHA-256 of the actual expected-text block is c92e902800898ec717a3dd3bee5eb3f256f3ca1b18810feb9cc45759a376fe01, not the declared 2d5e01a318d0f0879ab568c4be289c8b1f64ef8921a53c6277d5e069978baacb.
Required correction:
Preserve v3 unchanged as audit history and submit a complete replacement Work Plan v4 in a new comment.
In both JSON code blocks, encode U+000F with the six ASCII bytes 5c 75 30 30 30 66 (backslash, lowercase u, then 000f); do not use caret notation or an actual control byte in the comment.
Freeze one representation for which both JSON parses succeed, decoded string contains U+000F, UTF-8 length is 118, hex equals the existing declared vector, SHA-256 equals 2d5e01a318d0f0879ab568c4be289c8b1f64ef8921a53c6277d5e069978baacb, and canonicalize@3.0.0(JSON.parse(referenceInputText)) equals the expected canonical text byte-for-byte.
Keep the accepted correlated unions, compile-time/runtime matrix, exact 16 paths, exact two dependencies, and all v2 trust-boundary decisions unchanged.
Conclusion: SCOPE_CHANGES_REQUESTED. This is not SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED. Do not create the #26 branch/worktree, modify files or lockfile, install repository dependencies, commit, push, or open a PR. The old #25 execution environment is not cleared under this failed Scope Gate.
Final Implementation Work Plan v4 - M2-05 Quote Collection and Deterministic Selection - Awaiting Maintainer Scope Confirmation
0. Status, history, authority, and exact baseline
This is a complete, self-contained replacement proposal for the #26
implementation scope. It supersedes the prior Work Plan for future Scope Gate
purposes, but does not edit or delete history.
This v4 is a full, self-contained replacement proposal for the future Scope
Gate. It does not edit or delete v1, v2, v3, or any review comment.
All v3-accepted contracts remain unchanged: the exact 16 paths and two
dependencies; the sole public entry and optional AbortSignal port expansion;
server-owned catalog separated from untrusted request data; catalog provenance
not being Maintainer approval; freshness, immutable snapshot and content digest;
raw/source versus derived ownership; singular failure precedence; collector
terminality and late-settlement drainage without claiming source cancellation;
BigInt-only lossless ranking; deterministic byte tie-break; closed top-level and
correlated candidate unions; fixed selected digest; all non-goals and stop
conditions.
The only v4 correction is the RFC 8785 vector representation. Both JSON code
blocks now contain the literal six ASCII characters \u000f for U+000F.
No caret notation and no actual U+000F control byte are present in the comment.
The publication readback below is part of v4 acceptance.
Exact planning baseline was rechecked immediately before this comment:
proposed branch only after Scope Confirmation: codex/issue-26-quote-selection
proposed isolated worktree only after authorization: /Users/qy/Documents/moss-mini-demo-issue-26
This comment is planning only. It is not SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED, QA PASS, Review,
READY_TO_MERGE, Merge Gate, or merge authorization. No branch, worktree,
repository file, dependency, lockfile, commit, push, or PR is created by this
comment.
If origin/main changes before branch creation, Builder stops, rescans the
new main, and requests a new Scope Gate instead of implementing against this
baseline.
1. Goal and trust boundary
Add one server-only, deterministic Quote collection and candidate-selection
operation to the existing @moss-mini-demo/moss-adapter public entry.
The operation:
receives untrusted request data separately from server-owned asset catalog
configuration;
validates chain-143 comparison basis and catalog freshness/integrity;
records exactly one terminal outcome for every candidate;
preserves every acquired RawQuote separately from Mini-Demo-derived
snapshots and normalization;
selects only among eligible normalized outcomes using the disclosed rule;
returns either one selected candidate or an explicit no-eligible-candidate
result.
A Quote is protocol-selection context only. It is not Capability, simulation,
execution evidence, a best-trade claim, safety, approval, authorization, or a
cryptographic binding to a later Capability.
The only public rule identifier is:
DETERMINISTIC_CANDIDATE_SELECTION_V0_1
Public output and tests must not call the result best, optimal, safe, approved,
executable, guaranteed, or equivalent.
2. Exact 16-path writable list
Implementation may modify exactly these 16 repository paths and no others:
No public canonicalization helper, hash helper, comparator, catalog factory,
asset lookup helper, timer helper, second port, runtime Schema, or
source-binding bypass is added.
4. Exact dependencies and supply-chain policy
packages/moss-adapter/package.json adds exactly:
@moss-mini-demo/report-schema: workspace:*;
canonicalize: 3.0.0.
The existing server-only: 0.0.1 dependency remains unchanged.
The adapter consumes only the report-schema public package entry and reuses:
AssetSchema;
EvmAddressSchema;
ProtocolIdSchema;
PositiveAmountSchema;
UnsignedAmountSchema.
It does not import report-schema private source or copy those validators.
SHA-256 uses Node 22 node:crypto over canonical UTF-8 bytes. No second hash
dependency and no hand-written/approximate canonicalizer is allowed.
The lockfile may add only:
@moss-mini-demo/report-schema: workspace:* to the moss-adapter importer;
canonicalize: 3.0.0 to that importer;
the exact canonicalize@3.0.0 package/snapshot record.
No unrelated version refresh is accepted. pnpm-workspace.yaml and the sole 'sharp@0.34.5': true build permission remain byte-for-byte unchanged. No
second build-script permission may be added manually or by pnpm.
5. Untrusted request contract
QuoteCollectionRequestV0_1 is reject-only caller data:
each ProtocolId uses the accepted lowercase ASCII kebab grammar;
each array is unique; no trimming, sorting-as-repair, case folding, or
deduplication occurs;
chainId is exactly 143;
account is an exact EIP-55 non-zero address;
quoteInput.params.inputAsset, outputAsset, and amountIn exactly
equal the top-level basis;
additional params remain JSON only and cannot replace the required fields.
The request is cloned once inside a sanitized boundary. Getter, hostile/revoked
Proxy, cyclic/non-JSON input, duplicate protocol, invalid address, invalid
amount, wrong chain, or inconsistent duplicated basis throws a new MossAdapterError:
Amounts are canonical positive base-10 integer strings no larger than 2^256 - 1. Number, float, exponent, sign, whitespace, separator, leading
zero, zero, and over-uint256 forms are rejected. Ranking conversion uses only BigInt.
6. Asset identity and server-owned catalog boundary
symbol/name/icon/ticker/decimals do not establish identity;
no lowercasing, checksum repair, symbol lookup, address inference, or native
sentinel occurs.
The catalog is not inside QuoteCollectionRequestV0_1. It is injected
separately by the server composition owner. #26 provides no loader and commits
no production catalog/address. A later Web/API composition scope owns loading
and access control.
The catalog never claims MAINTAINER_APPROVED. Its provenance is only a
source-channel classification and does not prove approval, correctness, or live
evidence:
timestamps: calendar-valid canonical UTC with exactly millisecond precision, YYYY-MM-DDTHH:mm:ss.sssZ;
validFrom < validUntil;
freshness at collection start is validFrom <= new Date(Date.now()) < validUntil;
known decimals are safe integers 0..255;
entries are non-empty and asset identities are unique.
Catalog validation happens before any Quote call. Missing catalog, getter/Proxy,
wrong schema/chain, malformed source metadata, empty/duplicate entries,
conflicting duplicate decimals, invalid time interval, not-yet-valid catalog,
expired catalog, or clone/freeze failure throws the same stable INVALID_INPUT / quote error with zero delegations.
A structurally valid catalog may intentionally omit an asset or record UNKNOWN decimals:
requested asset absent -> every otherwise allowed candidate is SKIPPED
with UNKNOWN_ASSET, zero Quote calls;
requested asset decimals UNKNOWN -> every otherwise allowed candidate is SKIPPED with UNKNOWN_DECIMALS, zero Quote calls.
Synthetic tests must use provenance: "SYNTHETIC_TEST". Such a catalog is
test configuration only, not production/Maintainer-approved asset evidence. SERVER_CONFIGURED likewise identifies loading channel only and is not an
approval claim.
7. Catalog immutable snapshot and digest
After validation, the adapter:
creates an owned clone;
sorts entries by canonical asset-key UTF-8 bytes: ERC20:<EIP55 address> or NATIVE;
The digest proves only deterministic content identity of the owned catalog
snapshot. It does not authenticate who supplied it and is not approval or
chain evidence.
The catalog snapshot is included once in the top-level result. Normalized
quotes reference its identity/digest rather than copying authority claims.
8. Raw Quote projection and source/derived separation
Current RawQuote.mossOriginal.value remains complete opaque JsonValue. #26 does not rewrite, freeze, or replace it.
The collector takes one adapter-owned structured clone and extracts:
Only MALFORMED_QUOTE may carry UNSNAPSHOTTABLE. Every other acquired
outcome has SNAPSHOTTED.
The adapter never mutates or freezes source. Containers, snapshots,
catalog, normalized data, timing data, failures, digest payload, outcome array,
and result are frozen. Freezing a derived container must not recursively freeze
the source-owned RawQuote; implementation freezes owned fields explicitly.
each candidate gets exactly one terminal timing record;
acquired candidates name it acquiredTiming;
skipped/acquisition-failed candidates name it terminalTiming.
Timing is observation metadata. It is excluded from ranking, selected digest,
catalog digest, and deterministic selection fields.
#26 does not call action. The monotonic acquisition token only allows a
future authorized same-process orchestrator to calculate quote-to-action
elapsed time. Clock/process discontinuity is unprovable; wall-clock subtraction
must not replace the monotonic calculation.
Global invalid request/catalog throws MossAdapterError(INVALID_INPUT, quote)
before candidate outcomes exist.
Per-candidate precedence is exactly:
outside allowed set -> PROTOCOL_NOT_ALLOWED;
requested asset absent -> UNKNOWN_ASSET;
requested decimals unknown -> UNKNOWN_DECIMALS;
8,000 ms collector deadline -> QUOTE_TIMEOUT;
source reject/throw before deadline -> QUOTE_ACQUISITION_FAILED;
raw snapshot/projection/canonicalization invalid -> MALFORMED_QUOTE;
raw input/output asset differs -> ASSET_DIRECTION_MISMATCH;
raw amountIn differs -> AMOUNT_BASIS_MISMATCH;
otherwise -> ELIGIBLE.
Exactly one precedence result is retained per candidate. Later checks do not
overwrite an earlier failure.
An existing stable source MossAdapterError.code is retained only in the QUOTE_ACQUISITION_FAILED branch as sourceErrorCode: MossAdapterErrorCode | null. Generic/hostile exceptions
produce null. No raw exception, cause, message, URL, headers, account,
params, key, or source object is retained in that branch.
11. Exact correlated candidate outcome discriminated union
QuoteCandidateOutcomeV0_1 is exported exactly as the following literal
union. The three INELIGIBLE variants are separate union members; raw and failure are not independent unions.
Correlation is therefore part of the exported TypeScript contract:
MALFORMED_QUOTE may pair with either SNAPSHOTTED or UNSNAPSHOTTABLE from RawQuoteRetentionV0_1;
ASSET_DIRECTION_MISMATCH can pair only with SNAPSHOTTED;
AMOUNT_BASIS_MISMATCH can pair only with SNAPSHOTTED;
ELIGIBLE can pair only with SNAPSHOTTED and must contain normalized;
no branch has optional raw, timing, normalized, or failure fields.
packages/moss-adapter/test/contracts.test.ts must freeze compile-time evidence:
valid examples for both malformed raw-retention variants and both
snapshotted mismatch variants use satisfies QuoteCandidateOutcomeV0_1;
Extract plus an AssertNever<T extends never> assertion proves each UNSNAPSHOTTABLE mismatch intersection is never;
literal assignments for UNSNAPSHOTTABLE + ASSET_DIRECTION_MISMATCH and UNSNAPSHOTTABLE + AMOUNT_BASIS_MISMATCH are each guarded by @ts-expect-error, and typecheck fails if either directive becomes unused.
Runtime collector tests separately exercise malformed-snapshotted,
malformed-unsnapshottable, asset-mismatch-snapshotted, and
amount-mismatch-snapshotted outcomes and assert their exact keys. They also
assert that no produced asset/amount mismatch has raw.status === "UNSNAPSHOTTABLE".
Every candidate ProtocolId appears once. Outcomes are sorted by ProtocolId
UTF-8 byte order, not input or settlement order.
12. Normalized quote contract and lossless ranking
No division, multiplication, rounding, display unit, cross-asset conversion,
USD value, symbol, or Number is used. The maximum uint256 value is accepted.
Winner:
highest BigInt(normalizedAmountOut);
tie -> ProtocolId UTF-8 byte lexicographic ascending;
comparator uses TextEncoder and numeric byte comparison;
no localeCompare, collation, case folding, Unicode normalization,
candidate order, settlement order, time, random value, or environment input.
ProtocolId is canonical lowercase ASCII, so its UTF-8 and ASCII bytes coincide.
13. Port change and exact timeout semantics
This v4 still requests a new Scope Gate for the disclosed, backward-compatible
optional signal expansion:
#26 does not claim that the underlying source request was canceled. A
cooperative source may stop. A signal-ignoring source may still fulfill/reject
later; both paths are drained. Quote is required to be a read-only operation,
but this interface cannot prove absence of external effects in an unimplemented
real source.
No output or documentation may say “source canceled” or equivalent unless a
future concrete binding independently proves that behavior.
A bare Promise.race without preattached late-settlement drainage is
forbidden.
14. Exact selected digest and top-level result unions
SELECTED exists only when exactly one outcome is the deterministic winner.
The selected protocol references an ELIGIBLE outcome. NOT_SELECTED
exists only when zero outcomes are eligible. The full candidate list is always
present.
It is passed to canonicalize@3.0.0; canonical UTF-8 bytes are hashed once
with Node createHash("sha256"). Output is sha256: plus exactly 64 lowercase hex characters.
A canonicalization rejection, undefined result, invalid Unicode, or non-I-JSON
value yields MALFORMED_QUOTE; no fallback serializer exists.
The digest is only a deterministic fingerprint of selected Quote context. It
is not a signature, Capability digest, integrity proof, execution binding, or
evidence that a later Capability came from this Quote.
acquiredTiming, terminalTiming, candidate order, settlement order,
deadline, and wall/monotonic time are excluded from catalog digest, selected
digest, ranking, and selected subobject.
15. Frozen RFC 8785 conformance vector with one canonical representation
The implementation and publication-readback tests use the exact public values.json vector from the RFC 8785 reference test corpus:
Expected values are literal constants and are not regenerated from the
implementation under test. No actual U+000F byte, caret representation, or
competing golden text is accepted.
16. Frozen synthetic catalog and selected-Quote golden vectors
Tests must compare the fixed payload, canonical text, and expected hash
literally. Recomputing expected values using the code under test is not
acceptance evidence.
All addresses, protocol IDs, times, amounts, block values, raw values, catalog
metadata, and provenance in these vectors are synthetic test data.
17. Complete deterministic selection and timeout test matrix
packages/moss-adapter/test/quote.test.ts must cover:
exact request clone/reject boundary;
catalog separate from request and no self-approved authority field;
catalog grammar, clone, sort, freeze, freshness, digest, and non-mutation;
missing, duplicate, inconsistent, not-yet-valid, and stale catalog -> stable
INVALID_INPUT and zero delegations;
exact dependency/lockfile change and no build-policy change;
frozen install independent of historic artifacts;
focused, adapter, package-import, full, browser-bundle, and production tests
pass;
all fixed canonical text/byte/hash vectors pass literally;
RFC canonical text parses, encodes to the frozen bytes, hashes to the frozen
SHA, and equals canonicalize@3.0.0 output;
correlated compile-time/type-level and runtime outcome matrices pass;
all candidate branches and precedence rules pass;
no Number amount path, locale comparator, time-dependent selection, raw
mutation, late-promise mutation, unhandled rejection, or source-cancellation
overclaim;
existing workflow unchanged and exact pushed-head quality-gate SUCCESS;
a source operation is not read-only and timeout behavior could create
external mutation;
signal forwarding requires a sixth port method or required breaking
parameter;
any third dependency, build permission, runtime export, root script,
seventeenth path, workflow, docs, ADR, Schema, Web/API, or vendor change is
needed;
canonicalize identity/integrity differs;
fixed RFC/catalog/selected vectors do not reproduce exactly;
raw Quote cannot supply the fixed projection/block window;
implementation crosses into Capability, simulation, Alignment, Decision,
RPC, wallet, signing, or transaction behavior.
Rollback is one revert of the #26 implementation commit after merge, or removal
of only the unmerged #26 branch/PR. It must not revert #25/#24, edit main
directly, change the Moss gitlink, or modify protection/required checks.
22. Requested Maintainer decision
Please record one of:
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED, explicitly accepting this v4
comment, exact 16 paths, two dependencies, public API/unions, separate
catalog trust semantics, catalog digest/freshness, optional signal forwarding,
collector-only timeout claims, raw/normalized ownership, deterministic
selection, exact vectors, non-goals, and stop conditions; or
SCOPE_CHANGES_REQUESTED, naming the exact path, dependency, API, trust,
evidence, vector, or semantic decision that must change.
Builder may create only codex/issue-26-quote-selection in a new isolated worktree from the exact baseline above, after the old M2-04: Create moss-adapter package and public ports #25 execution environment is cleanly removed.
The sole public entry remains @moss-mini-demo/moss-adapter; the only new runtime export is collectAndSelectQuotesV0_1.
The implementation PR must remain Draft through Builder verification and independent QA.
This record authorizes only the frozen Work Plan v4 implementation scope. It is not QA PASS, Maintainer Review, READY_TO_MERGE, Merge Gate, or merge authorization.
current remote baseline remains origin/main@a0f3a3e8605812c9f0997059b4a30ea7a736022c.
Builder may now create a new isolated #26 worktree and the authorized codex/issue-26-quote-selection branch from that exact baseline. The old #25 branch/worktree must not be reused. If origin/main moves before creation, stop and return for a refreshed Scope Gate.
This handoff does not start QA, Review, READY_TO_MERGE, Merge Gate, or merge authorization.
Maintainer has independently inspected the current main@a0f3a3e8605812c9f0997059b4a30ea7a736022c version of packages/moss-adapter/test/server-only.test.ts.
Decision: YES, the seventeenth path is authorized, subject to the exact closed boundary below.
Reason
Frozen Work Plan v4 already requires all of the following:
the only new runtime export is collectAndSelectQuotesV0_1;
the public-entry smoke must observe exactly that one new runtime export;
focused, adapter, package-import, full, browser-bundle, and production tests pass.
The existing server-only.test.ts independently asserts the complete approved runtime-export allowlist for the source entry. Adding the v4-required runtime export necessarily makes that unchanged allowlist fail. Therefore the original 16-path list omitted one pre-existing test that must be updated to express the already-approved public contract. This amendment corrects the writable-path list; it does not expand product behavior or change the v4 contract.
Exact amendment
The authorized writable-path count changes from 16 to 17 by adding exactly:
packages/moss-adapter/test/server-only.test.ts
Within this seventeenth path, Builder may make exactly one semantic change:
add "collectAndSelectQuotesV0_1" to the expected runtime-export array in keeps the source entry limited to the approved runtime exports, preserving the array's default JavaScript sort order.
The resulting expected runtime-export list must be exactly:
No test may be removed, skipped, weakened, renamed, mocked differently, or broadened. No server-only behavior, import condition, subprocess assertion, type-only export assertion, package export map, dependency, production code, or other line in this file may change except formatting strictly required by the one inserted array member.
Unchanged authority and stop conditions
Work Plan v4 comment 5201269230, frozen at 2026-08-06T06:42:10Z with body SHA-256 f30f88dbe065a257a669d5c68e9f50abb7ae0495bd9232d7a69e5525a7322732, and the original SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED record remain authoritative in every other respect.
This is a v4 scope-list correction, not a new API/version decision and not authorization for #27 behavior.
Any eighteenth path, second change in server-only.test.ts, third dependency, extra runtime export, contract change, workflow change, root-script change, Web/API change, vendor change, or #27 behavior remains a stop condition requiring a new Maintainer decision.
Required handoff evidence
The eventual Implementation Report / QA Handoff must include:
the exact diff for packages/moss-adapter/test/server-only.test.ts;
proof that its only semantic delta is the single allowlist member;
exact 17-path changed-file inventory;
all v4 focused and full verification results;
exact-head CI result.
This amendment authorizes Builder Qy to continue implementation and run the complete test matrix. It is not QA PASS, READY_TO_MERGE, Merge Gate, or merge authorization.
main protection remains strict with required quality-gate, resolved conversations, linear history, enforced admins, no force-push/delete, and Maintainers-only push restrictions;
no auto-merge or admin bypass was used.
This audit completes Issue #26 only. It does not authorize Issue #27 implementation; #27 may enter planning only after its dependency-gate record and must receive a separate Work Plan Scope Gate before any implementation branch, commit, or PR.
Activity
pillowtalk-Qy commentedon Aug 6, 2026
DEPENDENCY_GATE_CLEARED / PLANNING_SLOT_ASSIGNED
Issue #25 has been squash-merged through PR #72 into
main@a0f3a3e8605812c9f0997059b4a30ea7a736022c.Merged-main
quality-gateis SUCCESS: https://github.com/Moss-Mini-Demo/moss-mini-demo/actions/runs/31070657110/job/92517725619Issue #26 is assigned to
pillowtalk-Qyand moved to Project In Progress solely to begin planning from this exact main baseline. The first required artifact is a closed Work Plan covering writable paths, public contracts, trust boundaries, tests, non-goals, and verification.No implementation branch, worktree, commit or PR is authorized before Maintainer
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED. In Progress is not QA PASS, Review, READY_TO_MERGE, Merge Gate, or merge authorization. Do not absorb #27 or later dependent behavior into this plan.The single Builder slot is #26. Issue #23 remains Ready/unassigned and #27 plus later dependent issues remain Blocked.
pillowtalk-Qy commentedon Aug 6, 2026
Final Implementation Work Plan - M2-05 Quote Collection and Deterministic Selection - Awaiting Maintainer Scope Confirmation
0. Status, authority, and exact baseline
Source:
M2-05: Implement quote collection and deterministic selection #26 (comment);
This comment is a planning artifact only. It requests a new Maintainer Scope
Gate. It is not implementation authorization, QA PASS, Review, Merge Gate, or
merge authorization.
Exact planning baseline:
origin/main@a0f3a3e8605812c9f0997059b4a30ea7a736022cfeat: add Moss adapter ports (#72)https://github.com/Moss-Mini-Demo/moss-mini-demo/actions/runs/31070657110/job/92517725619
codex/issue-26-quote-selection/Users/qy/Documents/moss-mini-demo-issue-26No branch, worktree, repository file, dependency, lockfile, commit, push, or PR
is created by this comment. If
origin/mainchanges before branch creation,Builder stops, rescans the new main, and requests a revised Scope Gate.
1. Goal and trust boundary
Add one server-only, deterministic quote collection and candidate-selection
operation to the existing
@moss-mini-demo/moss-adapterpublic entry.The operation:
metadata;
RawQuoteseparately from Mini-Demo-derivednormalization;
result.
A Quote is protocol-selection context only. It is not Capability, simulation,
execution evidence, a best-trade claim, a safety conclusion, authorization, or
a cryptographic binding to any later Capability.
The only approved wording/identifier for the selection rule is
DETERMINISTIC_CANDIDATE_SELECTION_V0_1. Public output and tests must not use“best”, “optimal”, “safe”, “approved”, “executable”, or equivalent language.
2. Exact writable paths
Implementation may modify exactly these 16 repository paths and no others:
pnpm-lock.yamlpackages/moss-adapter/package.jsonpackages/moss-adapter/src/types.tspackages/moss-adapter/src/source-bindings.tspackages/moss-adapter/src/production.tspackages/moss-adapter/src/fake.tspackages/moss-adapter/src/asset-catalog.ts(new)packages/moss-adapter/src/quote.ts(new)packages/moss-adapter/src/selection.ts(new)packages/moss-adapter/src/index.tspackages/moss-adapter/test/contracts.test.tspackages/moss-adapter/test/production.test.tspackages/moss-adapter/test/fake.test.tspackages/moss-adapter/test/quote.test.ts(new)packages/moss-adapter/test/selection.test.ts(new)packages/moss-adapter/test/public-entry.smoke.mjsExplicit metadata decisions:
packages/moss-adapter/src/types.ts: modified for the exact public andinternal contracts in this plan.
packages/moss-adapter/src/index.ts: modified only to add the exact exportslisted in Section 3.
packages/moss-adapter/package.json: modified only for the two exactdependencies in Section 4; the package name and sole
.export stayunchanged.
pnpm-lock.yaml: modified only for the moss-adapter importer andcanonicalize@3.0.0.package.json: no change.pnpm-workspace.yaml: no change.packages/moss-adapter/src/errors.ts: no change; per-candidate acquisitionfailures are data outcomes, not new thrown
MossAdapterErrorvariants.Any need for a seventeenth path, a report-schema source edit, a root script
change, a workflow edit, or another dependency is a stop condition requiring a
new Scope Gate.
3. Sole public entry and exact new API
The package keeps exactly one public entry:
@moss-mini-demo/moss-adapterThere is no subpath export and no import from a private
srcpath.Existing runtime and type exports remain. The only new runtime export is:
collectAndSelectQuotesV0_1Exact runtime signature:
The only new type exports are:
QuoteRequestOptionsV0_1;QuoteAssetV0_1;AssetCatalogV0_1;AssetCatalogEntryV0_1;DecimalsRecordV0_1;QuoteCollectionRequestV0_1;QuoteRawProjectionV0_1;NormalizedQuoteV0_1;QuoteCandidateFailureCodeV0_1;QuoteCandidateOutcomeV0_1;SelectedQuoteDigestV0_1;QuoteCollectionResultV0_1.No public canonicalization helper, hash helper, comparator, asset lookup helper,
timeout helper, second port, runtime Schema, or source-binding bypass is added.
4. Exact dependency and supply-chain decision
packages/moss-adapter/package.jsonadds exactly:@moss-mini-demo/report-schema: workspace:*;canonicalize: 3.0.0.The existing
server-only: 0.0.1dependency remains unchanged.The adapter consumes only the report-schema public package entry and reuses its
accepted
AssetSchema,EvmAddressSchema,ProtocolIdSchema,PositiveAmountSchema, andUnsignedAmountSchema. It does not importreport-schema private source paths and does not copy those validators.
RFC 8785 canonicalization uses the pinned
canonicalize@3.0.0implementation:sha512-yYLfHyDMIXRyRqsKBRLX023riFLpXY2YOfdtqKXZRZy9qsfOJ9U+4F9YZL7MEzL5+ziN2x2nlBvY/Voi3EBljA==The specification source is RFC 8785:
https://www.rfc-editor.org/info/rfc8785
SHA-256 uses Node 22's built-in
node:cryptoover the canonical UTF-8 bytes.No second hashing package is added. No hand-written or approximate JSON
canonicalizer is permitted.
pnpm-lock.yamlmay add only the two adapter importer entries and the exactcanonicalize@3.0.0package record. It must not refresh unrelated versions.pnpm-workspace.yamland the sole'sharp@0.34.5': truebuild permissionremain byte-for-byte unchanged. No second build-script permission may be
created or auto-added.
5. Exact request contract
QuoteCollectionRequestV0_1is an adapter-owned, reject-only input:The duplicated comparison basis is intentional. Before any binding call,
quoteInput.params.inputAsset,outputAsset, andamountInmust exactlymatch the top-level request values. Additional protocol-neutral JSON fields in
quoteInput.paramsare preserved and passed through, but they cannot replaceor alter the three required comparison fields.
The request is cloned once inside a sanitized input boundary. Getter, Proxy,
revoked Proxy, cyclic, non-JSON, duplicate protocol, invalid address, invalid
amount, non-143 chain, or inconsistent basis input throws a fresh
MossAdapterErrorwithcode: INVALID_INPUT,operation: quote, nocause, no original message, and zero Quote delegations.Amounts are canonical positive base-10 integer strings and must be at most
2^256 - 1. JavaScriptNumber, floats, exponent notation, signs,whitespace, separators, leading zeroes, zero, and values above uint256 are
rejected. Conversion for comparison uses only
BigInt.6. Asset identity and catalog contract
QuoteAssetV0_1is exactly the accepted report-schema asset union:Rules:
143;identity;
native-address substitution occurs.
AssetCatalogV0_1is supplied as Maintainer-approved configuration data; #26does not commit real token addresses. It contains:
Duplicate asset identities invalidate the catalog. An absent asset produces
UNKNOWN_ASSET; an explicitUNKNOWNdecimals record producesUNKNOWN_DECIMALS. Both fail closed before that candidate can becomeeligible. No default such as native=18 is inferred. No RPC, token contract,
symbol registry, or display metadata is consulted.
7. Exact raw Quote projection and preservation
Current
RawQuote.mossOriginal.valueremains the complete opaqueJsonValue. #26 does not rewrite that source value or weaken its identityboundary.
For normalization, the collector makes one adapter-owned structured clone of
the acquired raw value and extracts this required projection:
The raw top-level object may contain additional JSON fields. They remain in the
preserved raw source and owned snapshot but do not silently become normalized
fields.
Extraction reads exact named fields; it never reads a symbol or formatted
amount. Missing fields, getter/clone failures, nulls, JavaScript-number amounts,
float/exponent/negative/zero/leading-zero amounts, non-143 chain, invalid asset
shape, malformed block strings, or
fromBlock > toBlockproduce the fixedper-candidate code
MALFORMED_QUOTE.Every candidate outcome is retained in byte-stable protocol order:
RawQuoteby identity,deep-frozen adapter-owned raw snapshot, normalized quote, and timing evidence;
RawQuotebyidentity when it can be retained, owned snapshot when created, and the fixed
structured failure;
message, URL, header, account, params, key, or cause.
The collector never freezes, mutates, reorders, or replaces the source-owned
RawQuote. Derived snapshots and normalized records are separately labelledMini-Demo-derived data.
8. Closed per-candidate failure vocabulary
QuoteCandidateFailureCodeV0_1has exactly:Rules:
MossAdapterError.codemay be retained only as an optionalbounded
sourceErrorCode;{ status: "NOT_SELECTED", code: "NO_ELIGIBLE_QUOTE", method: "DETERMINISTIC_CANDIDATE_SELECTION_V0_1" };9. AbortSignal interface expansion and exact timeout behavior
This plan explicitly requests a new Scope Gate for a backward-compatible
expansion of the #25 port:
ProductionMossPort,FakeMossPort, andcreateBoundMossPortforwardthe exact signal. No other port method changes.
The collector:
AbortControllerper allowed candidate;QUOTE_TIMEOUTas that candidate's terminal outcome;every late settlement is consumed;
committed;
append, replace, or influence selection.
The aggregate uses
Promise.allSettledover the complete candidate task list.A bare
Promise.racewithout terminal late-result handling is forbidden.A candidate outside
allowedProtocolsreceivesPROTOCOL_NOT_ALLOWEDwithout invoking
port.quote.The Quote port contract for #26 is read-only and must honor
AbortSignal.Tests prove signal propagation, abort observation, late fulfillment/rejection
drainage, no unhandled rejection, no outcome mutation, and no selection
pollution. If a production binding cannot honor cancellation or cannot prove
its Quote call has no externally mutating side effect, implementation stops and
returns to Maintainer; #26 must not claim cancellation of an uncooperative
source.
10. Eligibility and deterministic selection order
Global request/catalog validation happens before any Quote delegation. For each
candidate, terminal classification uses this exact order:
PROTOCOL_NOT_ALLOWEDand no call;QUOTE_TIMEOUTorQUOTE_ACQUISITION_FAILED;MALFORMED_QUOTE;ASSET_DIRECTION_MISMATCH;amountInstring equality with the request basis; otherwiseAMOUNT_BASIS_MISMATCH;UNKNOWN_ASSET;KNOWNdecimals with approved source metadata; otherwiseUNKNOWN_DECIMALS;Because every eligible candidate must have the exact same output asset
identity, all output amounts use the same authoritative decimals. Lossless
normalization therefore does not divide, round, format, or convert display
units:
Input/output decimals records and their authority/version/provenance are
retained in
NormalizedQuoteV0_1. Conflicting decimals for one asset make thecatalog invalid. Cross-asset price conversion, USD normalization, symbol-based
comparison, rounding, and Number arithmetic are forbidden.
Winner:
comparisonAmountwins;protocolIdUTF-8 byte lexicographic ascending;TextEncoderbyte arrays and numeric byte comparison;localeCompare, locale collation, case folding, Unicode normalization,settlement order, candidate input order, wall time, and random values are
forbidden.
ProtocolId is already lowercase ASCII, so UTF-8 and ASCII bytes coincide.
Duplicate protocol IDs are rejected before collection.
All returned candidate outcomes are sorted by the same byte comparator,
independent of settlement order.
11. RFC 8785 selected-quote digest
The selected candidate contains:
The exact canonical payload is:
The payload is passed to
canonicalize@3.0.0; the returned RFC 8785 text isUTF-8 encoded and hashed once with Node
createHash("sha256"). Acanonicalization rejection, undefined result, invalid Unicode, or non-I-JSON
value is
MALFORMED_QUOTE; no fallback serializer is allowed.The digest is a reproducibility fingerprint for the selected Quote record. It
is not a signature, Capability digest, integrity proof, execution binding, or
evidence that a later Capability came from this exact Quote.
Tests include a published RFC 8785 canonicalization vector and a fixed SHA-256
golden vector. They also recompute the selected payload digest independently
through the pinned package. No approximate property sorter is tested or used.
12. Time and block evidence
For every acquired Quote:
acquiredAtis captured when the Quote settles, usingnew Date(Date.now()).toISOString(), and must be canonical UTC withmilliseconds;
acquiredMonotonicNsis the canonical unsigned decimal string returned byprocess.hrtime.bigint();NODE_PROCESS_HRTIME_V0_1;and uses unsigned decimal strings with
fromBlock <= toBlock.Missing or malformed block-window evidence produces
MALFORMED_QUOTE; it isnever replaced with the current time or an inferred block.
acquiredAt,acquiredMonotonicNs, deadlines, and settlement order areexcluded from the RFC 8785 digest and from the
selectionsubobject. Theycannot change eligibility, ranking, selected protocol, or digest.
#26 does not call
action. It only records the monotonic acquisition tokenneeded for a future authorized orchestrator to compute quote-to-action elapsed
time from the same process clock. A process/clock discontinuity must be treated
as unprovable by that future scope; wall-clock subtraction is not a substitute.
13. Required tests
All data is inline and synthetic. No real protocol, token, address, Quote, RPC,
wallet, key, Receipt, simulation, or chain record is used.
packages/moss-adapter/test/quote.test.tscovers:symbol;
over-uint256 rejection;
MALFORMED_QUOTE;selected digest.
packages/moss-adapter/test/selection.test.tscontains the complete matrixwith expected terminal outcome and selection:
selection, digest, and byte-ordered outcome identities;unchanged;
NO_ELIGIBLE_QUOTE;selectionand digest and no input mutation.Cancellation regressions assert the exact
AbortSignalreaches bothProduction and Fake bindings. Existing five-method, source-sanitization,
input-sanitization, identity, server-only, and Fake determinism tests remain
green.
The public-entry smoke must expect exactly one additional runtime export,
collectAndSelectQuotesV0_1, and must continue proving normal browser-likeimport failure through the existing server-only guard.
14. Implementation sequence after authorization
a0f3a3e8605812c9f0997059b4a30ea7a736022c.canonicalize@3.0.0; update only the allowed lockfile records.the five-method
MossPort.complete per-protocol outcome collection with
Promise.allSettled.exports, and prohibited wording.
Closes #26,wait for exact-head CI, and hand the frozen head to independent Pre-PR QA.
No implementation starts before an explicit
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZEDcomment accepts this plan,including the optional AbortSignal interface expansion and the two dependencies.
15. Verification and CI acceptance
Use Node
22.23.1and pnpm11.16.0. Final verification runs from a freshisolated checkout with no pre-existing
distor.next:node --version pnpm --version pnpm install --frozen-lockfile pnpm --filter @moss-mini-demo/moss-adapter build pnpm --filter @moss-mini-demo/moss-adapter typecheck pnpm vitest run packages/moss-adapter/test/quote.test.ts pnpm vitest run packages/moss-adapter/test/selection.test.ts pnpm vitest run packages/moss-adapter/test pnpm test:package-import pnpm build pnpm typecheck pnpm test pnpm check pnpm test:web:bundle pnpm test:web:production git diff --check origin/main...HEAD git diff --name-only origin/main...HEAD git status --shortAcceptance requires:
tests pass;
quality-gate;quality-gateis SUCCESS;16. Explicit non-goals
#26 does not implement:
transaction submission;
best-trade claim;
M2 issue.
No ADR, workflow, documentation, report-schema source, decision-engine,
Fixture, Issue/Project state, branch protection, required check, permission, or
main change is in scope.
17. Risks, stop conditions, and rollback
Primary risks:
Stop and return to Maintainer if:
script, or seventeenth path is needed;
Decision, Web/API, RPC, wallet, signing, or transaction behavior.
Rollback is one revert of the #26 implementation commit after merge, or removal
of only the unmerged #26 branch/PR. It must not revert #25/#24, alter main
directly, change the Moss gitlink, or modify protection/required checks.
18. Requested Maintainer decision
Please record one of:
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED, explicitly accepting theexact 16 paths, the two dependencies, the optional AbortSignal expansion,
the raw Quote projection, asset catalog contract, timeout behavior,
selection law, digest payload, and time exclusion; or
SCOPE_CHANGES_REQUESTED, naming the exact path, dependency, API, evidence,or semantic decision that must change.
Until that record exists, Builder status is:
WORK_PLAN_SUBMITTED / AWAITING_MAINTAINER_SCOPE_CONFIRMATIONNo implementation branch, worktree, file change, commit, push, or PR is
authorized.
pillowtalk-Qy commentedon Aug 6, 2026
SCOPE_CHANGES_REQUESTED
Reviewed Work Plan: #26 (comment)
Reviewed baseline:
main@a0f3a3e8605812c9f0997059b4a30ea7a736022cMaintainer Scope Gate result: CHANGES REQUESTED. Do not create the #26 implementation branch, worktree, commit or PR.
Items that are already acceptable
MossPortremains five methods, and the optionalAbortSignalchange toquoteis disclosed rather than hidden;actionor absorb simulation/Decision behavior;canonicalize@3.0.0metadata was independently verified: Apache-2.0, zero runtime dependencies, built-in type declaration, no install/build lifecycle script, and the stated registry integrity matches.1. Asset-catalog authority is currently self-asserted
assetCatalogis part of the same public, caller-controlledQuoteCollectionRequestV0_1, yet an entry may declareauthority: "MAINTAINER_APPROVED"andprovenance: "CONFIGURATION". Input cloning and shape validation cannot prove those claims. A caller can construct arbitrary decimals/source metadata and thereby make a candidate eligible under a false authority label.The revised plan must define a real trust boundary:
MAINTAINER_APPROVEDclaim and define the weaker caller-supplied semantics;sourceVersionandsourceReferencerather than “bounded ASCII”;No real address needs to be added by #26, but arbitrary request data must not be able to self-certify authority.
2. Public result and candidate unions are not exact enough
The plan names the exported types but does not freeze the complete shape of
QuoteCandidateOutcomeV0_1, the selected top-level result, normalized records, timing records, failure records or source-error retention. The prose leaves Builder decisions about discriminants, optional fields and field ownership.The revised plan must provide exact TypeScript-like discriminated shapes for:
NOT_SELECTEDtop-level results;sourceErrorCode;Each candidate must have exactly one terminal discriminant and one failure precedence outcome. No optional-field combination may imply contradictory success/failure states.
3. Timeout must not overclaim source cancellation
The collector-local 8,000 ms terminal timeout and late-promise drainage are sound, but the plan also says the production Quote binding “must honor”
AbortSignal. #25 provides an injected structural binding and this repository has no real protocol binding whose cancellation behavior can be proven in #26. Signal forwarding is testable; actual source cancellation is not guaranteed by the TypeScript interface.Revise the contract to distinguish:
QUOTE_TIMEOUTbecomes immutable;abort()is called;Add explicit cooperative and signal-ignoring late-fulfillment/late-rejection matrix cases.
4. RFC 8785 evidence must be frozen to exact vectors
The dependency and hashing direction are acceptable. The revised plan must identify the exact published RFC 8785 test vector(s), expected canonical UTF-8 text/bytes, and the exact fixed payload plus expected lowercase SHA-256 value used as the golden test. “A published vector” still leaves the implementation to invent the actual acceptance evidence.
Required resubmission
Leave this Work Plan unchanged as history and submit one complete revised Work Plan comment. Reconfirm the same main baseline, or refresh the entire plan if main moves. The revision must restate the full path list, dependencies, port change, exact public contracts, catalog authority, timeout semantics, digest/time rules, tests, non-goals and stop conditions.
#26 remains Open / Qy assigned / Project In Progress for planning only. This comment is not implementation authorization. #23 remains Ready/unassigned; #27 and later dependent issues remain Blocked.
pillowtalk-Qy commentedon Aug 6, 2026
Final Implementation Work Plan v2 - M2-05 Quote Collection and Deterministic Selection - Awaiting Maintainer Scope Confirmation
0. Status, history, authority, and exact baseline
This is a complete, self-contained replacement proposal for the #26
implementation scope. It supersedes the prior Work Plan for future Scope Gate
purposes, but does not edit or delete history.
Historical records retained:
M2-05: Implement quote collection and deterministic selection #26 (comment)
SCOPE_CHANGES_REQUESTED:M2-05: Implement quote collection and deterministic selection #26 (comment)
M2-05: Implement quote collection and deterministic selection #26 (comment)
The four requested corrections are incorporated throughout this full plan:
self-asserted Maintainer approval, and has a precise immutable source record;
and digest shape is a closed discriminated contract;
unproven underlying-source cancellation;
input, canonical text/bytes, and expected hashes.
Exact planning baseline was rechecked immediately before this comment:
origin/main@a0f3a3e8605812c9f0997059b4a30ea7a736022cfeat: add Moss adapter ports (#72)https://github.com/Moss-Mini-Demo/moss-mini-demo/actions/runs/31070657110/job/92517725619
codex/issue-26-quote-selection/Users/qy/Documents/moss-mini-demo-issue-26This comment is planning only. It is not
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED, QA PASS, Review,READY_TO_MERGE, Merge Gate, or merge authorization. No branch, worktree,
repository file, dependency, lockfile, commit, push, or PR is created by this
comment.
If
origin/mainchanges before branch creation, Builder stops, rescans thenew main, and requests a new Scope Gate instead of implementing against this
baseline.
1. Goal and trust boundary
Add one server-only, deterministic Quote collection and candidate-selection
operation to the existing
@moss-mini-demo/moss-adapterpublic entry.The operation:
configuration;
RawQuoteseparately from Mini-Demo-derivedsnapshots and normalization;
result.
A Quote is protocol-selection context only. It is not Capability, simulation,
execution evidence, a best-trade claim, safety, approval, authorization, or a
cryptographic binding to a later Capability.
The only public rule identifier is:
DETERMINISTIC_CANDIDATE_SELECTION_V0_1Public output and tests must not call the result best, optimal, safe, approved,
executable, guaranteed, or equivalent.
2. Exact 16-path writable list
Implementation may modify exactly these 16 repository paths and no others:
pnpm-lock.yamlpackages/moss-adapter/package.jsonpackages/moss-adapter/src/types.tspackages/moss-adapter/src/source-bindings.tspackages/moss-adapter/src/production.tspackages/moss-adapter/src/fake.tspackages/moss-adapter/src/asset-catalog.ts(new)packages/moss-adapter/src/quote.ts(new)packages/moss-adapter/src/selection.ts(new)packages/moss-adapter/src/index.tspackages/moss-adapter/test/contracts.test.tspackages/moss-adapter/test/production.test.tspackages/moss-adapter/test/fake.test.tspackages/moss-adapter/test/quote.test.ts(new)packages/moss-adapter/test/selection.test.ts(new)packages/moss-adapter/test/public-entry.smoke.mjsExact metadata decisions:
types.ts: yes, modified for the closed contracts in Sections 3, 5, 6, 8,9, 11, and 12.
index.ts: yes, modified only for the exact exports in Section 3.package.json: yes, modified only for the two dependencies inSection 4; package name and sole
.export remain unchanged.pnpm-lock.yaml: yes, modified only for the adapter importer and exactcanonicalize@3.0.0package record.package.json: no change.pnpm-workspace.yaml: no change.packages/moss-adapter/src/errors.ts: no change.Any seventeenth path, report-schema source edit, root script change, workflow
edit, build-permission change, documentation edit, or third dependency requires
a revised Scope Gate.
3. Sole public entry, runtime API, and type surface
The package keeps exactly one public entry:
@moss-mini-demo/moss-adapterNo subpath export or private
srcimport is permitted.All existing exports remain. The only new runtime export is:
collectAndSelectQuotesV0_1Exact signature:
The parameter order is part of the boundary:
requestis untrusted caller data;catalogis a separate server-composition dependency;global singleton by M2-05: Implement quote collection and deterministic selection #26.
The only new type exports are:
QuoteRequestOptionsV0_1;QuoteAssetV0_1;AssetCatalogV0_1;AssetCatalogEntryV0_1;DecimalsRecordV0_1;AssetCatalogSnapshotV0_1;QuoteCollectionRequestV0_1;QuoteRawProjectionV0_1;QuoteTimingV0_1;RawQuoteRetentionV0_1;NormalizedQuoteV0_1;QuoteCandidateFailureCodeV0_1;QuoteCandidateOutcomeV0_1;SelectedQuoteDigestV0_1;QuoteCollectionResultV0_1.No public canonicalization helper, hash helper, comparator, catalog factory,
asset lookup helper, timer helper, second port, runtime Schema, or
source-binding bypass is added.
4. Exact dependencies and supply-chain policy
packages/moss-adapter/package.jsonadds exactly:@moss-mini-demo/report-schema: workspace:*;canonicalize: 3.0.0.The existing
server-only: 0.0.1dependency remains unchanged.The adapter consumes only the report-schema public package entry and reuses:
AssetSchema;EvmAddressSchema;ProtocolIdSchema;PositiveAmountSchema;UnsignedAmountSchema.It does not import report-schema private source or copy those validators.
RFC 8785 canonicalization uses exact
canonicalize@3.0.0:https://www.npmjs.com/package/canonicalize/v/3.0.0
https://github.com/erdtman/canonicalize
https://www.rfc-editor.org/info/rfc8785
sha512-yYLfHyDMIXRyRqsKBRLX023riFLpXY2YOfdtqKXZRZy9qsfOJ9U+4F9YZL7MEzL5+ziN2x2nlBvY/Voi3EBljA==.SHA-256 uses Node 22
node:cryptoover canonical UTF-8 bytes. No second hashdependency and no hand-written/approximate canonicalizer is allowed.
The lockfile may add only:
@moss-mini-demo/report-schema: workspace:*to the moss-adapter importer;canonicalize: 3.0.0to that importer;canonicalize@3.0.0package/snapshot record.No unrelated version refresh is accepted.
pnpm-workspace.yamland the sole'sharp@0.34.5': truebuild permission remain byte-for-byte unchanged. Nosecond build-script permission may be added manually or by pnpm.
5. Untrusted request contract
QuoteCollectionRequestV0_1is reject-only caller data:Validation:
deduplication occurs;
chainIdis exactly143;quoteInput.params.inputAsset,outputAsset, andamountInexactlyequal the top-level basis;
The request is cloned once inside a sanitized boundary. Getter, hostile/revoked
Proxy, cyclic/non-JSON input, duplicate protocol, invalid address, invalid
amount, wrong chain, or inconsistent duplicated basis throws a new
MossAdapterError:Amounts are canonical positive base-10 integer strings no larger than
2^256 - 1. Number, float, exponent, sign, whitespace, separator, leadingzero, zero, and over-uint256 forms are rejected. Ranking conversion uses only
BigInt.6. Asset identity and server-owned catalog boundary
QuoteAssetV0_1is exactly:Rules:
143;sentinel occurs.
The catalog is not inside
QuoteCollectionRequestV0_1. It is injectedseparately by the server composition owner. #26 provides no loader and commits
no production catalog/address. A later Web/API composition scope owns loading
and access control.
The catalog never claims
MAINTAINER_APPROVED. Its provenance is only asource-channel classification and does not prove approval, correctness, or live
evidence:
Exact scalar grammar:
catalogId:^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$, length 1..64;sourceVersion:^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$,length 5..32;
sourceReference:^[a-z0-9][a-z0-9._:/@-]{0,127}$, length 1..128;YYYY-MM-DDTHH:mm:ss.sssZ;validFrom < validUntil;validFrom <= new Date(Date.now()) < validUntil;Catalog validation happens before any Quote call. Missing catalog, getter/Proxy,
wrong schema/chain, malformed source metadata, empty/duplicate entries,
conflicting duplicate decimals, invalid time interval, not-yet-valid catalog,
expired catalog, or clone/freeze failure throws the same stable
INVALID_INPUT / quoteerror with zero delegations.A structurally valid catalog may intentionally omit an asset or record
UNKNOWNdecimals:SKIPPEDwith
UNKNOWN_ASSET, zero Quote calls;UNKNOWN-> every otherwise allowed candidate isSKIPPEDwithUNKNOWN_DECIMALS, zero Quote calls.Synthetic tests must use
provenance: "SYNTHETIC_TEST". Such a catalog istest configuration only, not production/Maintainer-approved asset evidence.
SERVER_CONFIGUREDlikewise identifies loading channel only and is not anapproval claim.
7. Catalog immutable snapshot and digest
After validation, the adapter:
ERC20:<EIP55 address>orNATIVE;digest = "sha256:" + 64 lowercase hex.Exact result metadata:
The digest proves only deterministic content identity of the owned catalog
snapshot. It does not authenticate who supplied it and is not approval or
chain evidence.
The catalog snapshot is included once in the top-level result. Normalized
quotes reference its identity/digest rather than copying authority claims.
8. Raw Quote projection and source/derived separation
Current
RawQuote.mossOriginal.valueremains complete opaqueJsonValue.#26 does not rewrite, freeze, or replace it.
The collector takes one adapter-owned structured clone and extracts:
Additional raw JSON fields remain in both original raw source and owned
snapshot, but do not silently become normalized fields.
Missing fields, unsnapshotable raw data, invalid Unicode/non-I-JSON digest
material, number/float/exponent/signed/zero/leading-zero/over-uint256 amounts,
wrong chain, invalid asset, malformed block number, or
BigInt(fromBlock) > BigInt(toBlock)yieldsMALFORMED_QUOTE.Exact raw retention union:
Only
MALFORMED_QUOTEmay carryUNSNAPSHOTTABLE. Every other acquiredoutcome has
SNAPSHOTTED.The adapter never mutates or freezes
source. Containers, snapshots,catalog, normalized data, timing data, failures, digest payload, outcome array,
and result are frozen. Freezing a derived container must not recursively freeze
the source-owned
RawQuote; implementation freezes owned fields explicitly.9. Exact timing contract
observedAt = new Date(Date.now()).toISOString();monotonicNs = process.hrtime.bigint().toString(10);acquiredTiming;terminalTiming.Timing is observation metadata. It is excluded from ranking, selected digest,
catalog digest, and deterministic
selectionfields.#26 does not call
action. The monotonic acquisition token only allows afuture authorized same-process orchestrator to calculate quote-to-action
elapsed time. Clock/process discontinuity is unprovable; wall-clock subtraction
must not replace the monotonic calculation.
10. Closed failure vocabulary and precedence
QuoteCandidateFailureCodeV0_1is exactly:Global invalid request/catalog throws
MossAdapterError(INVALID_INPUT, quote)before candidate outcomes exist.
Per-candidate precedence is exactly:
PROTOCOL_NOT_ALLOWED;UNKNOWN_ASSET;UNKNOWN_DECIMALS;QUOTE_TIMEOUT;QUOTE_ACQUISITION_FAILED;MALFORMED_QUOTE;ASSET_DIRECTION_MISMATCH;AMOUNT_BASIS_MISMATCH;ELIGIBLE.Exactly one precedence result is retained per candidate. Later checks do not
overwrite an earlier failure.
An existing stable source
MossAdapterError.codeis retained only in theQUOTE_ACQUISITION_FAILEDbranch assourceErrorCode: MossAdapterErrorCode | null. Generic/hostile exceptionsproduce
null. No raw exception, cause, message, URL, headers, account,params, key, or source object is retained in that branch.
11. Exact candidate outcome discriminated union
Implementation refines the
INELIGIBLEbranch so:MALFORMED_QUOTEaccepts either raw-retention discriminant;raw.status: "SNAPSHOTTED".No branch has optional raw/timing/normalized/failure fields. There is no shape
that is simultaneously successful and failed.
Every candidate ProtocolId appears once. Outcomes are sorted by ProtocolId
UTF-8 byte order, not input or settlement order.
12. Normalized quote contract and lossless ranking
Every eligible candidate has exact request output-asset identity, so all output
amounts share one catalog decimals record. Normalization is lossless:
No division, multiplication, rounding, display unit, cross-asset conversion,
USD value, symbol, or Number is used. The maximum uint256 value is accepted.
Winner:
BigInt(normalizedAmountOut);TextEncoderand numeric byte comparison;localeCompare, collation, case folding, Unicode normalization,candidate order, settlement order, time, random value, or environment input.
ProtocolId is canonical lowercase ASCII, so its UTF-8 and ASCII bytes coincide.
13. Port change and exact timeout semantics
This v2 still requests a new Scope Gate for the disclosed, backward-compatible
optional signal expansion:
ProductionMossPort,FakeMossPort, andcreateBoundMossPortforwardthe exact signal. No other method changes. Existing two-argument calls remain
valid.
For each allowed, catalog-known candidate:
AbortController;port.quotecall;controller.abort("MOSS_MINI_DEMO_QUOTE_TIMEOUT_V0_1");QUOTE_TIMEOUToutcome;Promise.allSettled.Collector terminality is the local immutable state transition in step 5. It
does not depend on source cooperation.
Signal propagation guarantees only:
signal.aborted === trueafter deadline;signal.reason === "MOSS_MINI_DEMO_QUOTE_TIMEOUT_V0_1".#26 does not claim that the underlying source request was canceled. A
cooperative source may stop. A signal-ignoring source may still fulfill/reject
later; both paths are drained. Quote is required to be a read-only operation,
but this interface cannot prove absence of external effects in an unimplemented
real source.
No output or documentation may say “source canceled” or equivalent unless a
future concrete binding independently proves that behavior.
A bare
Promise.racewithout preattached late-settlement drainage isforbidden.
14. Exact selected digest and top-level result unions
SELECTEDexists only when exactly one outcome is the deterministic winner.The selected protocol references an
ELIGIBLEoutcome.NOT_SELECTEDexists only when zero outcomes are eligible. The full candidate list is always
present.
The selected digest payload is exactly:
It is passed to
canonicalize@3.0.0; canonical UTF-8 bytes are hashed oncewith Node
createHash("sha256"). Output issha256:plus exactly 64 lowercase hex characters.A canonicalization rejection, undefined result, invalid Unicode, or non-I-JSON
value yields
MALFORMED_QUOTE; no fallback serializer exists.The digest is only a deterministic fingerprint of selected Quote context. It
is not a signature, Capability digest, integrity proof, execution binding, or
evidence that a later Capability came from this Quote.
acquiredTiming,terminalTiming, candidate order, settlement order,deadline, and wall/monotonic time are excluded from catalog digest, selected
digest, ranking, and selected subobject.
15. Frozen RFC 8785 conformance vector
The implementation test must use the exact public
values.jsonvector fromthe RFC 8785 reference test corpus:
https://github.com/cyberphone/json-canonicalization/blob/master/testdata/input/values.json
https://github.com/cyberphone/json-canonicalization/blob/master/testdata/output/values.json
https://github.com/cyberphone/json-canonicalization/blob/master/testdata/outhex/values.txt
Exact canonical text, with the backslash escapes shown literally:
{"literals":[null,true,false],"numbers":[333333333.3333333,1e+30,4.5,0.002,1e-27],"string":"€$\u000f\nA'B\"\\\\\"/"}Exact canonical UTF-8 bytes in lowercase hexadecimal:
SHA-256 of those exact bytes:
2d5e01a318d0f0879ab568c4be289c8b1f64ef8921a53c6277d5e069978baacbThe test must compare canonical text, UTF-8 byte hex, and SHA. It must not
regenerate expected values from the implementation under test.
16. Frozen synthetic catalog and selected-Quote golden vectors
The test catalog source payload is exactly:
{ "schemaVersion": "moss-mini-demo/asset-catalog/0.1", "catalogId": "synthetic-assets", "sourceVersion": "1.0.0", "provenance": "SYNTHETIC_TEST", "sourceReference": "test/asset-catalog-v1", "chainId": 143, "validFrom": "2026-01-01T00:00:00.000Z", "validUntil": "2027-01-01T00:00:00.000Z", "entries": [ { "asset": { "kind": "ERC20", "address": "0x2222222222222222222222222222222222222222" }, "decimals": { "status": "KNOWN", "value": 6 } }, { "asset": { "kind": "NATIVE" }, "decimals": { "status": "KNOWN", "value": 18 } } ] }Expected canonical catalog text:
{"catalogId":"synthetic-assets","chainId":143,"entries":[{"asset":{"address":"0x2222222222222222222222222222222222222222","kind":"ERC20"},"decimals":{"status":"KNOWN","value":6}},{"asset":{"kind":"NATIVE"},"decimals":{"status":"KNOWN","value":18}}],"provenance":"SYNTHETIC_TEST","schemaVersion":"moss-mini-demo/asset-catalog/0.1","sourceReference":"test/asset-catalog-v1","sourceVersion":"1.0.0","validFrom":"2026-01-01T00:00:00.000Z","validUntil":"2027-01-01T00:00:00.000Z"}Expected catalog digest:
sha256:9f09d6a5e86f4ab1e459a7e0db1fd981afcbafe8cdc880e4e6b8e295dfc9a75eThe fixed selected-Quote digest payload is exactly:
{ "schemaVersion": "moss-mini-demo/selected-quote-digest/0.1", "chainId": 143, "protocolId": "alpha-protocol", "method": "swap", "account": "0x1111111111111111111111111111111111111111", "inputAsset": { "kind": "NATIVE" }, "outputAsset": { "kind": "ERC20", "address": "0x2222222222222222222222222222222222222222" }, "inputAmount": "1000000000000000000", "outputAmount": "42000000", "catalog": { "catalogId": "synthetic-assets", "sourceVersion": "1.0.0", "provenance": "SYNTHETIC_TEST", "sourceReference": "test/asset-catalog-v1", "digest": "sha256:9f09d6a5e86f4ab1e459a7e0db1fd981afcbafe8cdc880e4e6b8e295dfc9a75e" }, "inputDecimals": 18, "outputDecimals": 6, "observableBlockWindow": { "fromBlock": "100", "toBlock": "101" }, "mossSource": { "provenance": "SYNTHETIC_FAKE", "upstreamCommit": "1ae6b6322d51fae9104f047efb94e601050b967f", "integrationCommit": "1ae6b6322d51fae9104f047efb94e601050b967f", "patchsetDigest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "rawQuote": { "chainId": 143, "inputAsset": { "kind": "NATIVE" }, "outputAsset": { "kind": "ERC20", "address": "0x2222222222222222222222222222222222222222" }, "amountIn": "1000000000000000000", "amountOut": "42000000", "observableBlockWindow": { "fromBlock": "100", "toBlock": "101" }, "synthetic": true } }Expected canonical selected-Quote text:
{"account":"0x1111111111111111111111111111111111111111","catalog":{"catalogId":"synthetic-assets","digest":"sha256:9f09d6a5e86f4ab1e459a7e0db1fd981afcbafe8cdc880e4e6b8e295dfc9a75e","provenance":"SYNTHETIC_TEST","sourceReference":"test/asset-catalog-v1","sourceVersion":"1.0.0"},"chainId":143,"inputAmount":"1000000000000000000","inputAsset":{"kind":"NATIVE"},"inputDecimals":18,"method":"swap","mossSource":{"integrationCommit":"1ae6b6322d51fae9104f047efb94e601050b967f","patchsetDigest":"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","provenance":"SYNTHETIC_FAKE","upstreamCommit":"1ae6b6322d51fae9104f047efb94e601050b967f"},"observableBlockWindow":{"fromBlock":"100","toBlock":"101"},"outputAmount":"42000000","outputAsset":{"address":"0x2222222222222222222222222222222222222222","kind":"ERC20"},"outputDecimals":6,"protocolId":"alpha-protocol","rawQuote":{"amountIn":"1000000000000000000","amountOut":"42000000","chainId":143,"inputAsset":{"kind":"NATIVE"},"observableBlockWindow":{"fromBlock":"100","toBlock":"101"},"outputAsset":{"address":"0x2222222222222222222222222222222222222222","kind":"ERC20"},"synthetic":true},"schemaVersion":"moss-mini-demo/selected-quote-digest/0.1"}Expected selected-Quote digest:
sha256:b9ee24d4c1566c35b3282f4b15fc4d98551f4c2d199ea8221926bf09c8f37594Tests must compare the fixed payload, canonical text, and expected hash
literally. Recomputing expected values using the code under test is not
acceptance evidence.
All addresses, protocol IDs, times, amounts, block values, raw values, catalog
metadata, and provenance in these vectors are synthetic test data.
17. Complete deterministic selection and timeout test matrix
packages/moss-adapter/test/quote.test.tsmust cover:INVALID_INPUT and zero delegations;
SYNTHETIC_TEST;over-uint256 rejection;
MALFORMED_QUOTE;digest, and selected digest.
packages/moss-adapter/test/selection.test.tsmust cover the following exactmatrix and expected discriminants:
ELIGIBLE, secondELIGIBLE,top
SELECTEDfirst;SELECTEDsecond;selected protocol, catalog digest, and selected digest;
SKIPPED/PROTOCOL_NOT_ALLOWED, zero call for it;SKIPPED/UNKNOWN_ASSET, zero Quote calls;SKIPPED/UNKNOWN_DECIMALS, zero Quote calls;ACQUISITION_FAILED/QUOTE_TIMEOUT;no mutation/selection pollution;
no unhandled rejection;
retained with safe sourceErrorCode/null;
INELIGIBLE, eligible selected;UNSNAPSHOTTABLE, no source leak;INELIGIBLE/ASSET_DIRECTION_MISMATCH;INELIGIBLE/AMOUNT_BASIS_MISMATCH;NOT_SELECTED/NO_ELIGIBLE_QUOTE;retained under its single precedence code;
and no input mutation.
Additional regressions:
quotecalls remain valid;collectAndSelectQuotesV0_1;server-only;The aggregate must use
Promise.allSettled, retain one terminal outcome percandidate, and return byte-ordered frozen outcomes.
18. Implementation sequence after authorization
a0f3a3e8605812c9f0997059b4a30ea7a736022c.codex/issue-26-quote-selectionand the approved isolatedworktree.
changing the five-method port.
digest.
drainage, and
Promise.allSettled.selected digest.
source immutability, prohibited wording, and fixed vectors.
Closes #26, wait for exact-head CI, postImplementation Report and Pre-PR QA Handoff, then freeze the Head.
No implementation action occurs before a Maintainer explicitly accepts v2 with
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED.19. Local and CI verification
Use Node
22.23.1and pnpm11.16.0. Final evidence runs from a freshisolated checkout with no pre-existing
distor.next:node --version pnpm --version pnpm install --frozen-lockfile pnpm --filter @moss-mini-demo/moss-adapter build pnpm --filter @moss-mini-demo/moss-adapter typecheck pnpm vitest run packages/moss-adapter/test/quote.test.ts pnpm vitest run packages/moss-adapter/test/selection.test.ts pnpm vitest run packages/moss-adapter/test pnpm test:package-import pnpm build pnpm typecheck pnpm test pnpm check pnpm test:web:bundle pnpm test:web:production git diff --check origin/main...HEAD git diff --name-only origin/main...HEAD git status --shortAcceptance requires:
pass;
mutation, late-promise mutation, unhandled rejection, or source-cancellation
overclaim;
quality-gateSUCCESS;20. Explicit non-goals
#26 does not implement:
claims;
behavior.
No ADR, workflow, docs, report-schema source, decision-engine, Fixture,
Issue/Project state, branch protection, required check, permission, main, Moss
gitlink, or
.gitmoduleschange is in scope.21. Risks, stop conditions, and rollback
Primary risks:
Stop and return to Maintainer if:
external mutation;
parameter;
seventeenth path, workflow, docs, ADR, Schema, Web/API, or vendor change is
needed;
RPC, wallet, signing, or transaction behavior.
Rollback is one revert of the #26 implementation commit after merge, or removal
of only the unmerged #26 branch/PR. It must not revert #25/#24, edit main
directly, change the Moss gitlink, or modify protection/required checks.
22. Requested Maintainer decision
Please record one of:
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED, explicitly accepting this v2comment, exact 16 paths, two dependencies, public API/unions, separate
catalog trust semantics, catalog digest/freshness, optional signal forwarding,
collector-only timeout claims, raw/normalized ownership, deterministic
selection, exact vectors, non-goals, and stop conditions; or
SCOPE_CHANGES_REQUESTED, naming the exact path, dependency, API, trust,evidence, vector, or semantic decision that must change.
Until that decision exists:
WORK_PLAN_V2_SUBMITTED / AWAITING_MAINTAINER_SCOPE_CONFIRMATIONNo implementation branch, worktree, file change, dependency installation,
lockfile generation, commit, push, or PR is authorized.
pillowtalk-Qy commentedon Aug 6, 2026
SCOPE_CHANGES_REQUESTED - Work Plan v2
Reviewed Work Plan v2: #26 (comment)
Reviewed baseline:
main@a0f3a3e8605812c9f0997059b4a30ea7a736022cMaintainer Scope Gate result: CHANGES REQUESTED. No #26 implementation branch, worktree, dependency install, lockfile generation, commit or PR is authorized.
Items now accepted
Two exact blockers remain.
1.
INELIGIBLEunion still permits contradictory statesThe published
QuoteCandidateOutcomeV0_1gives theINELIGIBLEbranch:Because
RawQuoteRetentionV0_1includesstatus: "UNSNAPSHOTTABLE", the actual exported type accepts both contradictory combinations:UNSNAPSHOTTABLE + ASSET_DIRECTION_MISMATCH;UNSNAPSHOTTABLE + AMOUNT_BASIS_MISMATCH.The following prose says implementation will refine this, but prose does not change the public TypeScript contract. The type itself must make invalid combinations unrepresentable. Define exact correlated branches, for example:
MALFORMED_QUOTEwithRawQuoteRetentionV0_1;ASSET_DIRECTION_MISMATCHwithSNAPSHOTTEDonly;AMOUNT_BASIS_MISMATCHwithSNAPSHOTTEDonly.Freeze the literal exported union in the revised plan and add compile-time/type-level plus runtime matrix evidence for the forbidden combinations.
2. RFC 8785 canonical text contradicts its bytes and SHA
Section 15 labels this exact text as canonical:
The actual v2 block renders the U+000F position as backslash-caret-O (
5c 5e 4f). Backslash-caret is not a valid JSON escape. The declared canonical byte vector instead encodes5c 75 30 30 30 66(the six ASCII bytes for a lowercase Unicode escape of U+000F).Independent calculation gives:
c92e902800898ec717a3dd3bee5eb3f256f3ca1b18810feb9cc45759a376fe01;2d5e01a318d0f0879ab568c4be289c8b1f64ef8921a53c6277d5e069978baacb.The declared byte vector and second hash agree with the RFC 8785 reference vector; the printed canonical text does not. Replace it with exact valid canonical JSON using the lowercase six-character Unicode escape for U+000F, then independently prove all three representations are identical:
canonicalize@3.0.0output equals the same text.Do not retain two competing golden representations.
Required resubmission
Keep v1 and v2 unchanged as audit history. Submit one complete, self-contained Work Plan v3 with the exact correlated public union and corrected RFC vector reproduced throughout. Reconfirm the baseline and restate all 16 paths, two dependencies, catalog boundary, timeout semantics, full public shapes, vectors, tests, non-goals and stop conditions.
#26 remains Open / Qy assigned / Project In Progress for planning only. #23 remains Ready/unassigned; #27 and later dependent Issues remain Blocked. Scope authorization and local environment cleanup remain deferred.
pillowtalk-Qy commentedon Aug 6, 2026
Final Implementation Work Plan v3 - M2-05 Quote Collection and Deterministic Selection - Awaiting Maintainer Scope Confirmation
0. Status, history, authority, and exact baseline
This is a complete, self-contained replacement proposal for the #26
implementation scope. It supersedes the prior Work Plan for future Scope Gate
purposes, but does not edit or delete history.
Historical records retained unchanged:
M2-05: Implement quote collection and deterministic selection #26 (comment)
SCOPE_CHANGES_REQUESTEDon v1:M2-05: Implement quote collection and deterministic selection #26 (comment)
M2-05: Implement quote collection and deterministic selection #26 (comment)
SCOPE_CHANGES_REQUESTED - Work Plan v2:M2-05: Implement quote collection and deterministic selection #26 (comment)
M2-05: Implement quote collection and deterministic selection #26 (comment)
This v3 is a full replacement proposal for the future Scope Gate. It does not
edit or delete v1, v2, or either review comment.
All boundaries accepted during the v2 review remain unchanged: the catalog is
separate from untrusted request data; catalog provenance is not Maintainer
approval; failure precedence is singular; timeout proves collector terminality
and signal propagation only; late fulfillment/rejection is drained; BigInt,
timing exclusion, raw ownership, Quote-not-execution-evidence language, the
exact 16 paths, and the exact two dependencies remain fixed.
The two remaining v2 blockers are corrected throughout this complete plan:
QuoteCandidateOutcomeV0_1now contains three separatelycorrelated
INELIGIBLEbranches, makingUNSNAPSHOTTABLE + ASSET_DIRECTION_MISMATCHandUNSNAPSHOTTABLE + AMOUNT_BASIS_MISMATCHunrepresentable;\u000f, and the plan freezes one canonical text whose UTF-8 bytes, bytevector, SHA-256, and
canonicalize@3.0.0output must all be identical.Exact planning baseline was rechecked immediately before this comment:
origin/main@a0f3a3e8605812c9f0997059b4a30ea7a736022cfeat: add Moss adapter ports (#72)https://github.com/Moss-Mini-Demo/moss-mini-demo/actions/runs/31070657110/job/92517725619
codex/issue-26-quote-selection/Users/qy/Documents/moss-mini-demo-issue-26This comment is planning only. It is not
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED, QA PASS, Review,READY_TO_MERGE, Merge Gate, or merge authorization. No branch, worktree,
repository file, dependency, lockfile, commit, push, or PR is created by this
comment.
If
origin/mainchanges before branch creation, Builder stops, rescans thenew main, and requests a new Scope Gate instead of implementing against this
baseline.
1. Goal and trust boundary
Add one server-only, deterministic Quote collection and candidate-selection
operation to the existing
@moss-mini-demo/moss-adapterpublic entry.The operation:
configuration;
RawQuoteseparately from Mini-Demo-derivedsnapshots and normalization;
result.
A Quote is protocol-selection context only. It is not Capability, simulation,
execution evidence, a best-trade claim, safety, approval, authorization, or a
cryptographic binding to a later Capability.
The only public rule identifier is:
DETERMINISTIC_CANDIDATE_SELECTION_V0_1Public output and tests must not call the result best, optimal, safe, approved,
executable, guaranteed, or equivalent.
2. Exact 16-path writable list
Implementation may modify exactly these 16 repository paths and no others:
pnpm-lock.yamlpackages/moss-adapter/package.jsonpackages/moss-adapter/src/types.tspackages/moss-adapter/src/source-bindings.tspackages/moss-adapter/src/production.tspackages/moss-adapter/src/fake.tspackages/moss-adapter/src/asset-catalog.ts(new)packages/moss-adapter/src/quote.ts(new)packages/moss-adapter/src/selection.ts(new)packages/moss-adapter/src/index.tspackages/moss-adapter/test/contracts.test.tspackages/moss-adapter/test/production.test.tspackages/moss-adapter/test/fake.test.tspackages/moss-adapter/test/quote.test.ts(new)packages/moss-adapter/test/selection.test.ts(new)packages/moss-adapter/test/public-entry.smoke.mjsExact metadata decisions:
types.ts: yes, modified for the closed contracts in Sections 3, 5, 6, 8,9, 11, and 12.
index.ts: yes, modified only for the exact exports in Section 3.package.json: yes, modified only for the two dependencies inSection 4; package name and sole
.export remain unchanged.pnpm-lock.yaml: yes, modified only for the adapter importer and exactcanonicalize@3.0.0package record.package.json: no change.pnpm-workspace.yaml: no change.packages/moss-adapter/src/errors.ts: no change.Any seventeenth path, report-schema source edit, root script change, workflow
edit, build-permission change, documentation edit, or third dependency requires
a revised Scope Gate.
3. Sole public entry, runtime API, and type surface
The package keeps exactly one public entry:
@moss-mini-demo/moss-adapterNo subpath export or private
srcimport is permitted.All existing exports remain. The only new runtime export is:
collectAndSelectQuotesV0_1Exact signature:
The parameter order is part of the boundary:
requestis untrusted caller data;catalogis a separate server-composition dependency;global singleton by M2-05: Implement quote collection and deterministic selection #26.
The only new type exports are:
QuoteRequestOptionsV0_1;QuoteAssetV0_1;AssetCatalogV0_1;AssetCatalogEntryV0_1;DecimalsRecordV0_1;AssetCatalogSnapshotV0_1;QuoteCollectionRequestV0_1;QuoteRawProjectionV0_1;QuoteTimingV0_1;RawQuoteRetentionV0_1;NormalizedQuoteV0_1;QuoteCandidateFailureCodeV0_1;QuoteCandidateOutcomeV0_1;SelectedQuoteDigestV0_1;QuoteCollectionResultV0_1.No public canonicalization helper, hash helper, comparator, catalog factory,
asset lookup helper, timer helper, second port, runtime Schema, or
source-binding bypass is added.
4. Exact dependencies and supply-chain policy
packages/moss-adapter/package.jsonadds exactly:@moss-mini-demo/report-schema: workspace:*;canonicalize: 3.0.0.The existing
server-only: 0.0.1dependency remains unchanged.The adapter consumes only the report-schema public package entry and reuses:
AssetSchema;EvmAddressSchema;ProtocolIdSchema;PositiveAmountSchema;UnsignedAmountSchema.It does not import report-schema private source or copy those validators.
RFC 8785 canonicalization uses exact
canonicalize@3.0.0:https://www.npmjs.com/package/canonicalize/v/3.0.0
https://github.com/erdtman/canonicalize
https://www.rfc-editor.org/info/rfc8785
sha512-yYLfHyDMIXRyRqsKBRLX023riFLpXY2YOfdtqKXZRZy9qsfOJ9U+4F9YZL7MEzL5+ziN2x2nlBvY/Voi3EBljA==.SHA-256 uses Node 22
node:cryptoover canonical UTF-8 bytes. No second hashdependency and no hand-written/approximate canonicalizer is allowed.
The lockfile may add only:
@moss-mini-demo/report-schema: workspace:*to the moss-adapter importer;canonicalize: 3.0.0to that importer;canonicalize@3.0.0package/snapshot record.No unrelated version refresh is accepted.
pnpm-workspace.yamland the sole'sharp@0.34.5': truebuild permission remain byte-for-byte unchanged. Nosecond build-script permission may be added manually or by pnpm.
5. Untrusted request contract
QuoteCollectionRequestV0_1is reject-only caller data:Validation:
deduplication occurs;
chainIdis exactly143;quoteInput.params.inputAsset,outputAsset, andamountInexactlyequal the top-level basis;
The request is cloned once inside a sanitized boundary. Getter, hostile/revoked
Proxy, cyclic/non-JSON input, duplicate protocol, invalid address, invalid
amount, wrong chain, or inconsistent duplicated basis throws a new
MossAdapterError:Amounts are canonical positive base-10 integer strings no larger than
2^256 - 1. Number, float, exponent, sign, whitespace, separator, leadingzero, zero, and over-uint256 forms are rejected. Ranking conversion uses only
BigInt.6. Asset identity and server-owned catalog boundary
QuoteAssetV0_1is exactly:Rules:
143;sentinel occurs.
The catalog is not inside
QuoteCollectionRequestV0_1. It is injectedseparately by the server composition owner. #26 provides no loader and commits
no production catalog/address. A later Web/API composition scope owns loading
and access control.
The catalog never claims
MAINTAINER_APPROVED. Its provenance is only asource-channel classification and does not prove approval, correctness, or live
evidence:
Exact scalar grammar:
catalogId:^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$, length 1..64;sourceVersion:^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$,length 5..32;
sourceReference:^[a-z0-9][a-z0-9._:/@-]{0,127}$, length 1..128;YYYY-MM-DDTHH:mm:ss.sssZ;validFrom < validUntil;validFrom <= new Date(Date.now()) < validUntil;Catalog validation happens before any Quote call. Missing catalog, getter/Proxy,
wrong schema/chain, malformed source metadata, empty/duplicate entries,
conflicting duplicate decimals, invalid time interval, not-yet-valid catalog,
expired catalog, or clone/freeze failure throws the same stable
INVALID_INPUT / quoteerror with zero delegations.A structurally valid catalog may intentionally omit an asset or record
UNKNOWNdecimals:SKIPPEDwith
UNKNOWN_ASSET, zero Quote calls;UNKNOWN-> every otherwise allowed candidate isSKIPPEDwithUNKNOWN_DECIMALS, zero Quote calls.Synthetic tests must use
provenance: "SYNTHETIC_TEST". Such a catalog istest configuration only, not production/Maintainer-approved asset evidence.
SERVER_CONFIGUREDlikewise identifies loading channel only and is not anapproval claim.
7. Catalog immutable snapshot and digest
After validation, the adapter:
ERC20:<EIP55 address>orNATIVE;digest = "sha256:" + 64 lowercase hex.Exact result metadata:
The digest proves only deterministic content identity of the owned catalog
snapshot. It does not authenticate who supplied it and is not approval or
chain evidence.
The catalog snapshot is included once in the top-level result. Normalized
quotes reference its identity/digest rather than copying authority claims.
8. Raw Quote projection and source/derived separation
Current
RawQuote.mossOriginal.valueremains complete opaqueJsonValue.#26 does not rewrite, freeze, or replace it.
The collector takes one adapter-owned structured clone and extracts:
Additional raw JSON fields remain in both original raw source and owned
snapshot, but do not silently become normalized fields.
Missing fields, unsnapshotable raw data, invalid Unicode/non-I-JSON digest
material, number/float/exponent/signed/zero/leading-zero/over-uint256 amounts,
wrong chain, invalid asset, malformed block number, or
BigInt(fromBlock) > BigInt(toBlock)yieldsMALFORMED_QUOTE.Exact raw retention union:
Only
MALFORMED_QUOTEmay carryUNSNAPSHOTTABLE. Every other acquiredoutcome has
SNAPSHOTTED.The adapter never mutates or freezes
source. Containers, snapshots,catalog, normalized data, timing data, failures, digest payload, outcome array,
and result are frozen. Freezing a derived container must not recursively freeze
the source-owned
RawQuote; implementation freezes owned fields explicitly.9. Exact timing contract
observedAt = new Date(Date.now()).toISOString();monotonicNs = process.hrtime.bigint().toString(10);acquiredTiming;terminalTiming.Timing is observation metadata. It is excluded from ranking, selected digest,
catalog digest, and deterministic
selectionfields.#26 does not call
action. The monotonic acquisition token only allows afuture authorized same-process orchestrator to calculate quote-to-action
elapsed time. Clock/process discontinuity is unprovable; wall-clock subtraction
must not replace the monotonic calculation.
10. Closed failure vocabulary and precedence
QuoteCandidateFailureCodeV0_1is exactly:Global invalid request/catalog throws
MossAdapterError(INVALID_INPUT, quote)before candidate outcomes exist.
Per-candidate precedence is exactly:
PROTOCOL_NOT_ALLOWED;UNKNOWN_ASSET;UNKNOWN_DECIMALS;QUOTE_TIMEOUT;QUOTE_ACQUISITION_FAILED;MALFORMED_QUOTE;ASSET_DIRECTION_MISMATCH;AMOUNT_BASIS_MISMATCH;ELIGIBLE.Exactly one precedence result is retained per candidate. Later checks do not
overwrite an earlier failure.
An existing stable source
MossAdapterError.codeis retained only in theQUOTE_ACQUISITION_FAILEDbranch assourceErrorCode: MossAdapterErrorCode | null. Generic/hostile exceptionsproduce
null. No raw exception, cause, message, URL, headers, account,params, key, or source object is retained in that branch.
11. Exact correlated candidate outcome discriminated union
QuoteCandidateOutcomeV0_1is exported exactly as the following literalunion. The three
INELIGIBLEvariants are separate union members;rawandfailureare not independent unions.Correlation is therefore part of the exported TypeScript contract:
MALFORMED_QUOTEmay pair with eitherSNAPSHOTTEDorUNSNAPSHOTTABLEfromRawQuoteRetentionV0_1;ASSET_DIRECTION_MISMATCHcan pair only withSNAPSHOTTED;AMOUNT_BASIS_MISMATCHcan pair only withSNAPSHOTTED;ELIGIBLEcan pair only withSNAPSHOTTEDand must containnormalized;packages/moss-adapter/test/contracts.test.tsmust freeze compile-time evidence:snapshotted mismatch variants use
satisfies QuoteCandidateOutcomeV0_1;Extractplus anAssertNever<T extends never>assertion proves eachUNSNAPSHOTTABLEmismatch intersection isnever;UNSNAPSHOTTABLE + ASSET_DIRECTION_MISMATCHandUNSNAPSHOTTABLE + AMOUNT_BASIS_MISMATCHare each guarded by@ts-expect-error, and typecheck fails if either directive becomes unused.Runtime collector tests separately exercise malformed-snapshotted,
malformed-unsnapshottable, asset-mismatch-snapshotted, and
amount-mismatch-snapshotted outcomes and assert their exact keys. They also
assert that no produced asset/amount mismatch has
raw.status === "UNSNAPSHOTTABLE".Every candidate ProtocolId appears once. Outcomes are sorted by ProtocolId
UTF-8 byte order, not input or settlement order.
12. Normalized quote contract and lossless ranking
Every eligible candidate has exact request output-asset identity, so all output
amounts share one catalog decimals record. Normalization is lossless:
No division, multiplication, rounding, display unit, cross-asset conversion,
USD value, symbol, or Number is used. The maximum uint256 value is accepted.
Winner:
BigInt(normalizedAmountOut);TextEncoderand numeric byte comparison;localeCompare, collation, case folding, Unicode normalization,candidate order, settlement order, time, random value, or environment input.
ProtocolId is canonical lowercase ASCII, so its UTF-8 and ASCII bytes coincide.
13. Port change and exact timeout semantics
This v3 still requests a new Scope Gate for the disclosed, backward-compatible
optional signal expansion:
ProductionMossPort,FakeMossPort, andcreateBoundMossPortforwardthe exact signal. No other method changes. Existing two-argument calls remain
valid.
For each allowed, catalog-known candidate:
AbortController;port.quotecall;controller.abort("MOSS_MINI_DEMO_QUOTE_TIMEOUT_V0_1");QUOTE_TIMEOUToutcome;Promise.allSettled.Collector terminality is the local immutable state transition in step 5. It
does not depend on source cooperation.
Signal propagation guarantees only:
signal.aborted === trueafter deadline;signal.reason === "MOSS_MINI_DEMO_QUOTE_TIMEOUT_V0_1".#26 does not claim that the underlying source request was canceled. A
cooperative source may stop. A signal-ignoring source may still fulfill/reject
later; both paths are drained. Quote is required to be a read-only operation,
but this interface cannot prove absence of external effects in an unimplemented
real source.
No output or documentation may say “source canceled” or equivalent unless a
future concrete binding independently proves that behavior.
A bare
Promise.racewithout preattached late-settlement drainage isforbidden.
14. Exact selected digest and top-level result unions
SELECTEDexists only when exactly one outcome is the deterministic winner.The selected protocol references an
ELIGIBLEoutcome.NOT_SELECTEDexists only when zero outcomes are eligible. The full candidate list is always
present.
The selected digest payload is exactly:
It is passed to
canonicalize@3.0.0; canonical UTF-8 bytes are hashed oncewith Node
createHash("sha256"). Output issha256:plus exactly 64 lowercase hex characters.A canonicalization rejection, undefined result, invalid Unicode, or non-I-JSON
value yields
MALFORMED_QUOTE; no fallback serializer exists.The digest is only a deterministic fingerprint of selected Quote context. It
is not a signature, Capability digest, integrity proof, execution binding, or
evidence that a later Capability came from this Quote.
acquiredTiming,terminalTiming, candidate order, settlement order,deadline, and wall/monotonic time are excluded from catalog digest, selected
digest, ranking, and selected subobject.
15. Frozen RFC 8785 conformance vector with one canonical representation
The implementation test uses the exact public
values.jsonvector from theRFC 8785 reference test corpus:
https://github.com/cyberphone/json-canonicalization/blob/master/testdata/input/values.json
https://github.com/cyberphone/json-canonicalization/blob/master/testdata/output/values.json
https://github.com/cyberphone/json-canonicalization/blob/master/testdata/outhex/values.txt
Exact reference input text:
{ "numbers": [333333333.33333329, 1E30, 4.50, 2e-3, 0.000000000000000000000000001], "string": "\u20ac$\u000F\u000aA'\u0042\u0022\u005c\\\"\/", "literals": [null, true, false] }The single exact canonical text is the following valid JSON. The U+000F
position is represented by the literal six ASCII characters
\u000f;there is no caret notation and no second text representation.
{"literals":[null,true,false],"numbers":[333333333.3333333,1e+30,4.5,0.002,1e-27],"string":"€$\u000f\nA'B\"\\\\\"/"}Exact UTF-8 bytes of that canonical text, in lowercase hexadecimal:
The exact byte count is
118. SHA-256 of those exact bytes is:2d5e01a318d0f0879ab568c4be289c8b1f64ef8921a53c6277d5e069978baacbThe test freezes these four independent equality checks:
JSON.parse(expectedCanonicalText)succeeds, and the decoded controlcharacter is U+000F;
Buffer.from(expectedCanonicalText, "utf8")is exactly 118 bytes and itshex equals the frozen byte vector above;
canonicalize@3.0.0(JSON.parse(referenceInputText))equalsexpectedCanonicalTextbyte-for-byte.The expected text, bytes, and SHA are literal constants taken from the
reference corpus and independently frozen in the test. Expected values must
not be regenerated from the implementation under test. There is no fallback
serializer and no competing golden representation.
16. Frozen synthetic catalog and selected-Quote golden vectors
The test catalog source payload is exactly:
{ "schemaVersion": "moss-mini-demo/asset-catalog/0.1", "catalogId": "synthetic-assets", "sourceVersion": "1.0.0", "provenance": "SYNTHETIC_TEST", "sourceReference": "test/asset-catalog-v1", "chainId": 143, "validFrom": "2026-01-01T00:00:00.000Z", "validUntil": "2027-01-01T00:00:00.000Z", "entries": [ { "asset": { "kind": "ERC20", "address": "0x2222222222222222222222222222222222222222" }, "decimals": { "status": "KNOWN", "value": 6 } }, { "asset": { "kind": "NATIVE" }, "decimals": { "status": "KNOWN", "value": 18 } } ] }Expected canonical catalog text:
{"catalogId":"synthetic-assets","chainId":143,"entries":[{"asset":{"address":"0x2222222222222222222222222222222222222222","kind":"ERC20"},"decimals":{"status":"KNOWN","value":6}},{"asset":{"kind":"NATIVE"},"decimals":{"status":"KNOWN","value":18}}],"provenance":"SYNTHETIC_TEST","schemaVersion":"moss-mini-demo/asset-catalog/0.1","sourceReference":"test/asset-catalog-v1","sourceVersion":"1.0.0","validFrom":"2026-01-01T00:00:00.000Z","validUntil":"2027-01-01T00:00:00.000Z"}Expected catalog digest:
sha256:9f09d6a5e86f4ab1e459a7e0db1fd981afcbafe8cdc880e4e6b8e295dfc9a75eThe fixed selected-Quote digest payload is exactly:
{ "schemaVersion": "moss-mini-demo/selected-quote-digest/0.1", "chainId": 143, "protocolId": "alpha-protocol", "method": "swap", "account": "0x1111111111111111111111111111111111111111", "inputAsset": { "kind": "NATIVE" }, "outputAsset": { "kind": "ERC20", "address": "0x2222222222222222222222222222222222222222" }, "inputAmount": "1000000000000000000", "outputAmount": "42000000", "catalog": { "catalogId": "synthetic-assets", "sourceVersion": "1.0.0", "provenance": "SYNTHETIC_TEST", "sourceReference": "test/asset-catalog-v1", "digest": "sha256:9f09d6a5e86f4ab1e459a7e0db1fd981afcbafe8cdc880e4e6b8e295dfc9a75e" }, "inputDecimals": 18, "outputDecimals": 6, "observableBlockWindow": { "fromBlock": "100", "toBlock": "101" }, "mossSource": { "provenance": "SYNTHETIC_FAKE", "upstreamCommit": "1ae6b6322d51fae9104f047efb94e601050b967f", "integrationCommit": "1ae6b6322d51fae9104f047efb94e601050b967f", "patchsetDigest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "rawQuote": { "chainId": 143, "inputAsset": { "kind": "NATIVE" }, "outputAsset": { "kind": "ERC20", "address": "0x2222222222222222222222222222222222222222" }, "amountIn": "1000000000000000000", "amountOut": "42000000", "observableBlockWindow": { "fromBlock": "100", "toBlock": "101" }, "synthetic": true } }Expected canonical selected-Quote text:
{"account":"0x1111111111111111111111111111111111111111","catalog":{"catalogId":"synthetic-assets","digest":"sha256:9f09d6a5e86f4ab1e459a7e0db1fd981afcbafe8cdc880e4e6b8e295dfc9a75e","provenance":"SYNTHETIC_TEST","sourceReference":"test/asset-catalog-v1","sourceVersion":"1.0.0"},"chainId":143,"inputAmount":"1000000000000000000","inputAsset":{"kind":"NATIVE"},"inputDecimals":18,"method":"swap","mossSource":{"integrationCommit":"1ae6b6322d51fae9104f047efb94e601050b967f","patchsetDigest":"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","provenance":"SYNTHETIC_FAKE","upstreamCommit":"1ae6b6322d51fae9104f047efb94e601050b967f"},"observableBlockWindow":{"fromBlock":"100","toBlock":"101"},"outputAmount":"42000000","outputAsset":{"address":"0x2222222222222222222222222222222222222222","kind":"ERC20"},"outputDecimals":6,"protocolId":"alpha-protocol","rawQuote":{"amountIn":"1000000000000000000","amountOut":"42000000","chainId":143,"inputAsset":{"kind":"NATIVE"},"observableBlockWindow":{"fromBlock":"100","toBlock":"101"},"outputAsset":{"address":"0x2222222222222222222222222222222222222222","kind":"ERC20"},"synthetic":true},"schemaVersion":"moss-mini-demo/selected-quote-digest/0.1"}Expected selected-Quote digest:
sha256:b9ee24d4c1566c35b3282f4b15fc4d98551f4c2d199ea8221926bf09c8f37594Tests must compare the fixed payload, canonical text, and expected hash
literally. Recomputing expected values using the code under test is not
acceptance evidence.
All addresses, protocol IDs, times, amounts, block values, raw values, catalog
metadata, and provenance in these vectors are synthetic test data.
17. Complete deterministic selection and timeout test matrix
packages/moss-adapter/test/quote.test.tsmust cover:INVALID_INPUT and zero delegations;
SYNTHETIC_TEST;over-uint256 rejection;
MALFORMED_QUOTE;satisfiesexamples for every correlatedINELIGIBLEbranch;
AssertNeverand@ts-expect-errorevidence that both unsnapshottablemismatch combinations are forbidden by the exported type;
vector from Section 15;
digest, and selected digest.
packages/moss-adapter/test/selection.test.tsmust cover the following exactmatrix and expected discriminants:
ELIGIBLE, secondELIGIBLE,top
SELECTEDfirst;SELECTEDsecond;selected protocol, catalog digest, and selected digest;
SKIPPED/PROTOCOL_NOT_ALLOWED, zero call for it;SKIPPED/UNKNOWN_ASSET, zero Quote calls;SKIPPED/UNKNOWN_DECIMALS, zero Quote calls;ACQUISITION_FAILED/QUOTE_TIMEOUT;no mutation/selection pollution;
no unhandled rejection;
retained with safe sourceErrorCode/null;
INELIGIBLE, eligible selected;UNSNAPSHOTTABLE, no source leak;INELIGIBLE/ASSET_DIRECTION_MISMATCH;INELIGIBLE/AMOUNT_BASIS_MISMATCH;NOT_SELECTED/NO_ELIGIBLE_QUOTE;retained under its single precedence code;
and no input mutation.
The correlated-union runtime matrix additionally asserts:
INELIGIBLE/MALFORMED_QUOTE;INELIGIBLE/MALFORMED_QUOTE;INELIGIBLE/ASSET_DIRECTION_MISMATCHwithraw.status: "SNAPSHOTTED";INELIGIBLE/AMOUNT_BASIS_MISMATCHwithraw.status: "SNAPSHOTTED";UNSNAPSHOTTABLE.Additional regressions:
quotecalls remain valid;collectAndSelectQuotesV0_1;server-only;The aggregate must use
Promise.allSettled, retain one terminal outcome percandidate, and return byte-ordered frozen outcomes.
18. Implementation sequence after authorization
a0f3a3e8605812c9f0997059b4a30ea7a736022c.codex/issue-26-quote-selectionand the approved isolatedworktree.
changing the five-method port.
digest.
drainage, and
Promise.allSettled.selected digest.
source immutability, prohibited wording, and fixed vectors.
Closes #26, wait for exact-head CI, postImplementation Report and Pre-PR QA Handoff, then freeze the Head.
No implementation action occurs before a Maintainer explicitly accepts v3 with
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED.19. Local and CI verification
Use Node
22.23.1and pnpm11.16.0. Final evidence runs from a freshisolated checkout with no pre-existing
distor.next:node --version pnpm --version pnpm install --frozen-lockfile pnpm --filter @moss-mini-demo/moss-adapter build pnpm --filter @moss-mini-demo/moss-adapter typecheck pnpm vitest run packages/moss-adapter/test/quote.test.ts pnpm vitest run packages/moss-adapter/test/selection.test.ts pnpm vitest run packages/moss-adapter/test pnpm test:package-import pnpm build pnpm typecheck pnpm test pnpm check pnpm test:web:bundle pnpm test:web:production git diff --check origin/main...HEAD git diff --name-only origin/main...HEAD git status --shortAcceptance requires:
pass;
SHA, and equals
canonicalize@3.0.0output;mutation, late-promise mutation, unhandled rejection, or source-cancellation
overclaim;
quality-gateSUCCESS;20. Explicit non-goals
#26 does not implement:
claims;
behavior.
No ADR, workflow, docs, report-schema source, decision-engine, Fixture,
Issue/Project state, branch protection, required check, permission, main, Moss
gitlink, or
.gitmoduleschange is in scope.21. Risks, stop conditions, and rollback
Primary risks:
Stop and return to Maintainer if:
external mutation;
parameter;
seventeenth path, workflow, docs, ADR, Schema, Web/API, or vendor change is
needed;
RPC, wallet, signing, or transaction behavior.
Rollback is one revert of the #26 implementation commit after merge, or removal
of only the unmerged #26 branch/PR. It must not revert #25/#24, edit main
directly, change the Moss gitlink, or modify protection/required checks.
22. Requested Maintainer decision
Please record one of:
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED, explicitly accepting this v3comment, exact 16 paths, two dependencies, public API/unions, separate
catalog trust semantics, catalog digest/freshness, optional signal forwarding,
collector-only timeout claims, raw/normalized ownership, deterministic
selection, exact vectors, non-goals, and stop conditions; or
SCOPE_CHANGES_REQUESTED, naming the exact path, dependency, API, trust,evidence, vector, or semantic decision that must change.
Until that decision exists:
WORK_PLAN_V3_SUBMITTED / AWAITING_MAINTAINER_SCOPE_CONFIRMATIONNo implementation branch, worktree, file change, dependency installation,
lockfile generation, commit, push, or PR is authorized.
pillowtalk-Qy commentedon Aug 6, 2026
SCOPE_CHANGES_REQUESTED - Work Plan v3
Frozen review object:
6c536abfc1d1b9ed68fdd9ee8b6a1290ab8672f6f50acd9d1c750deb4dc9107fupdated_at:2026-08-06T05:58:07Zmain@a0f3a3e8605812c9f0997059b4a30ea7a736022cThe v2 correlated-union blocker is resolved at plan level. The exported union has separate malformed, asset-mismatch, and amount-mismatch members; both forbidden
UNSNAPSHOTTABLEmismatch combinations are unrepresentable. The proposed compile-timesatisfies/AssertNever/@ts-expect-errorchecks and the runtime correlation matrix are adequate. The previously accepted catalog authority, timeout and late-drainage, BigInt, digest, raw-evidence, and Quote-not-execution-evidence boundaries remain intact. The scope remains exactly 16 paths and two dependencies, with no #27 behavior.One P0 vector blocker remains in Sections 0 and 15:
5c 5e 4f), not the required six-byte JSON escape: backslash, lowercaseu, and four hex digits000f(hex5c 75 30 30 30 66).JSON.parse(referenceInputText)fails at line 3 column 22 with a bad escaped character.JSON.parse(expectedCanonicalText)fails at line 1 column 96 with a bad escaped character.5c5e4f; the declared vector is 118 bytes and contains5c7530303066.c92e902800898ec717a3dd3bee5eb3f256f3ca1b18810feb9cc45759a376fe01, not the declared2d5e01a318d0f0879ab568c4be289c8b1f64ef8921a53c6277d5e069978baacb.Required correction:
5c 75 30 30 30 66(backslash, lowercaseu, then000f); do not use caret notation or an actual control byte in the comment.2d5e01a318d0f0879ab568c4be289c8b1f64ef8921a53c6277d5e069978baacb, andcanonicalize@3.0.0(JSON.parse(referenceInputText))equals the expected canonical text byte-for-byte.Conclusion:
SCOPE_CHANGES_REQUESTED. This is notSCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED. Do not create the #26 branch/worktree, modify files or lockfile, install repository dependencies, commit, push, or open a PR. The old #25 execution environment is not cleared under this failed Scope Gate.pillowtalk-Qy commentedon Aug 6, 2026
Final Implementation Work Plan v4 - M2-05 Quote Collection and Deterministic Selection - Awaiting Maintainer Scope Confirmation
0. Status, history, authority, and exact baseline
This is a complete, self-contained replacement proposal for the #26
implementation scope. It supersedes the prior Work Plan for future Scope Gate
purposes, but does not edit or delete history.
Historical records retained unchanged:
M2-05: Implement quote collection and deterministic selection #26 (comment)
SCOPE_CHANGES_REQUESTEDon v1:M2-05: Implement quote collection and deterministic selection #26 (comment)
M2-05: Implement quote collection and deterministic selection #26 (comment)
SCOPE_CHANGES_REQUESTED - Work Plan v2:M2-05: Implement quote collection and deterministic selection #26 (comment)
M2-05: Implement quote collection and deterministic selection #26 (comment)
SCOPE_CHANGES_REQUESTED - Work Plan v3:M2-05: Implement quote collection and deterministic selection #26 (comment)
M2-05: Implement quote collection and deterministic selection #26 (comment)
This v4 is a full, self-contained replacement proposal for the future Scope
Gate. It does not edit or delete v1, v2, v3, or any review comment.
All v3-accepted contracts remain unchanged: the exact 16 paths and two
dependencies; the sole public entry and optional AbortSignal port expansion;
server-owned catalog separated from untrusted request data; catalog provenance
not being Maintainer approval; freshness, immutable snapshot and content digest;
raw/source versus derived ownership; singular failure precedence; collector
terminality and late-settlement drainage without claiming source cancellation;
BigInt-only lossless ranking; deterministic byte tie-break; closed top-level and
correlated candidate unions; fixed selected digest; all non-goals and stop
conditions.
The only v4 correction is the RFC 8785 vector representation. Both JSON code
blocks now contain the literal six ASCII characters \u000f for U+000F.
No caret notation and no actual U+000F control byte are present in the comment.
The publication readback below is part of v4 acceptance.
Exact planning baseline was rechecked immediately before this comment:
origin/main@a0f3a3e8605812c9f0997059b4a30ea7a736022cfeat: add Moss adapter ports (#72)https://github.com/Moss-Mini-Demo/moss-mini-demo/actions/runs/31070657110/job/92517725619
codex/issue-26-quote-selection/Users/qy/Documents/moss-mini-demo-issue-26This comment is planning only. It is not
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED, QA PASS, Review,READY_TO_MERGE, Merge Gate, or merge authorization. No branch, worktree,
repository file, dependency, lockfile, commit, push, or PR is created by this
comment.
If
origin/mainchanges before branch creation, Builder stops, rescans thenew main, and requests a new Scope Gate instead of implementing against this
baseline.
1. Goal and trust boundary
Add one server-only, deterministic Quote collection and candidate-selection
operation to the existing
@moss-mini-demo/moss-adapterpublic entry.The operation:
configuration;
RawQuoteseparately from Mini-Demo-derivedsnapshots and normalization;
result.
A Quote is protocol-selection context only. It is not Capability, simulation,
execution evidence, a best-trade claim, safety, approval, authorization, or a
cryptographic binding to a later Capability.
The only public rule identifier is:
DETERMINISTIC_CANDIDATE_SELECTION_V0_1Public output and tests must not call the result best, optimal, safe, approved,
executable, guaranteed, or equivalent.
2. Exact 16-path writable list
Implementation may modify exactly these 16 repository paths and no others:
pnpm-lock.yamlpackages/moss-adapter/package.jsonpackages/moss-adapter/src/types.tspackages/moss-adapter/src/source-bindings.tspackages/moss-adapter/src/production.tspackages/moss-adapter/src/fake.tspackages/moss-adapter/src/asset-catalog.ts(new)packages/moss-adapter/src/quote.ts(new)packages/moss-adapter/src/selection.ts(new)packages/moss-adapter/src/index.tspackages/moss-adapter/test/contracts.test.tspackages/moss-adapter/test/production.test.tspackages/moss-adapter/test/fake.test.tspackages/moss-adapter/test/quote.test.ts(new)packages/moss-adapter/test/selection.test.ts(new)packages/moss-adapter/test/public-entry.smoke.mjsExact metadata decisions:
types.ts: yes, modified for the closed contracts in Sections 3, 5, 6, 8,9, 11, and 12.
index.ts: yes, modified only for the exact exports in Section 3.package.json: yes, modified only for the two dependencies inSection 4; package name and sole
.export remain unchanged.pnpm-lock.yaml: yes, modified only for the adapter importer and exactcanonicalize@3.0.0package record.package.json: no change.pnpm-workspace.yaml: no change.packages/moss-adapter/src/errors.ts: no change.Any seventeenth path, report-schema source edit, root script change, workflow
edit, build-permission change, documentation edit, or third dependency requires
a revised Scope Gate.
3. Sole public entry, runtime API, and type surface
The package keeps exactly one public entry:
@moss-mini-demo/moss-adapterNo subpath export or private
srcimport is permitted.All existing exports remain. The only new runtime export is:
collectAndSelectQuotesV0_1Exact signature:
The parameter order is part of the boundary:
requestis untrusted caller data;catalogis a separate server-composition dependency;global singleton by M2-05: Implement quote collection and deterministic selection #26.
The only new type exports are:
QuoteRequestOptionsV0_1;QuoteAssetV0_1;AssetCatalogV0_1;AssetCatalogEntryV0_1;DecimalsRecordV0_1;AssetCatalogSnapshotV0_1;QuoteCollectionRequestV0_1;QuoteRawProjectionV0_1;QuoteTimingV0_1;RawQuoteRetentionV0_1;NormalizedQuoteV0_1;QuoteCandidateFailureCodeV0_1;QuoteCandidateOutcomeV0_1;SelectedQuoteDigestV0_1;QuoteCollectionResultV0_1.No public canonicalization helper, hash helper, comparator, catalog factory,
asset lookup helper, timer helper, second port, runtime Schema, or
source-binding bypass is added.
4. Exact dependencies and supply-chain policy
packages/moss-adapter/package.jsonadds exactly:@moss-mini-demo/report-schema: workspace:*;canonicalize: 3.0.0.The existing
server-only: 0.0.1dependency remains unchanged.The adapter consumes only the report-schema public package entry and reuses:
AssetSchema;EvmAddressSchema;ProtocolIdSchema;PositiveAmountSchema;UnsignedAmountSchema.It does not import report-schema private source or copy those validators.
RFC 8785 canonicalization uses exact
canonicalize@3.0.0:https://www.npmjs.com/package/canonicalize/v/3.0.0
https://github.com/erdtman/canonicalize
https://www.rfc-editor.org/info/rfc8785
sha512-yYLfHyDMIXRyRqsKBRLX023riFLpXY2YOfdtqKXZRZy9qsfOJ9U+4F9YZL7MEzL5+ziN2x2nlBvY/Voi3EBljA==.SHA-256 uses Node 22
node:cryptoover canonical UTF-8 bytes. No second hashdependency and no hand-written/approximate canonicalizer is allowed.
The lockfile may add only:
@moss-mini-demo/report-schema: workspace:*to the moss-adapter importer;canonicalize: 3.0.0to that importer;canonicalize@3.0.0package/snapshot record.No unrelated version refresh is accepted.
pnpm-workspace.yamland the sole'sharp@0.34.5': truebuild permission remain byte-for-byte unchanged. Nosecond build-script permission may be added manually or by pnpm.
5. Untrusted request contract
QuoteCollectionRequestV0_1is reject-only caller data:Validation:
deduplication occurs;
chainIdis exactly143;quoteInput.params.inputAsset,outputAsset, andamountInexactlyequal the top-level basis;
The request is cloned once inside a sanitized boundary. Getter, hostile/revoked
Proxy, cyclic/non-JSON input, duplicate protocol, invalid address, invalid
amount, wrong chain, or inconsistent duplicated basis throws a new
MossAdapterError:Amounts are canonical positive base-10 integer strings no larger than
2^256 - 1. Number, float, exponent, sign, whitespace, separator, leadingzero, zero, and over-uint256 forms are rejected. Ranking conversion uses only
BigInt.6. Asset identity and server-owned catalog boundary
QuoteAssetV0_1is exactly:Rules:
143;sentinel occurs.
The catalog is not inside
QuoteCollectionRequestV0_1. It is injectedseparately by the server composition owner. #26 provides no loader and commits
no production catalog/address. A later Web/API composition scope owns loading
and access control.
The catalog never claims
MAINTAINER_APPROVED. Its provenance is only asource-channel classification and does not prove approval, correctness, or live
evidence:
Exact scalar grammar:
catalogId:^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$, length 1..64;sourceVersion:^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$,length 5..32;
sourceReference:^[a-z0-9][a-z0-9._:/@-]{0,127}$, length 1..128;YYYY-MM-DDTHH:mm:ss.sssZ;validFrom < validUntil;validFrom <= new Date(Date.now()) < validUntil;Catalog validation happens before any Quote call. Missing catalog, getter/Proxy,
wrong schema/chain, malformed source metadata, empty/duplicate entries,
conflicting duplicate decimals, invalid time interval, not-yet-valid catalog,
expired catalog, or clone/freeze failure throws the same stable
INVALID_INPUT / quoteerror with zero delegations.A structurally valid catalog may intentionally omit an asset or record
UNKNOWNdecimals:SKIPPEDwith
UNKNOWN_ASSET, zero Quote calls;UNKNOWN-> every otherwise allowed candidate isSKIPPEDwithUNKNOWN_DECIMALS, zero Quote calls.Synthetic tests must use
provenance: "SYNTHETIC_TEST". Such a catalog istest configuration only, not production/Maintainer-approved asset evidence.
SERVER_CONFIGUREDlikewise identifies loading channel only and is not anapproval claim.
7. Catalog immutable snapshot and digest
After validation, the adapter:
ERC20:<EIP55 address>orNATIVE;digest = "sha256:" + 64 lowercase hex.Exact result metadata:
The digest proves only deterministic content identity of the owned catalog
snapshot. It does not authenticate who supplied it and is not approval or
chain evidence.
The catalog snapshot is included once in the top-level result. Normalized
quotes reference its identity/digest rather than copying authority claims.
8. Raw Quote projection and source/derived separation
Current
RawQuote.mossOriginal.valueremains complete opaqueJsonValue.#26 does not rewrite, freeze, or replace it.
The collector takes one adapter-owned structured clone and extracts:
Additional raw JSON fields remain in both original raw source and owned
snapshot, but do not silently become normalized fields.
Missing fields, unsnapshotable raw data, invalid Unicode/non-I-JSON digest
material, number/float/exponent/signed/zero/leading-zero/over-uint256 amounts,
wrong chain, invalid asset, malformed block number, or
BigInt(fromBlock) > BigInt(toBlock)yieldsMALFORMED_QUOTE.Exact raw retention union:
Only
MALFORMED_QUOTEmay carryUNSNAPSHOTTABLE. Every other acquiredoutcome has
SNAPSHOTTED.The adapter never mutates or freezes
source. Containers, snapshots,catalog, normalized data, timing data, failures, digest payload, outcome array,
and result are frozen. Freezing a derived container must not recursively freeze
the source-owned
RawQuote; implementation freezes owned fields explicitly.9. Exact timing contract
observedAt = new Date(Date.now()).toISOString();monotonicNs = process.hrtime.bigint().toString(10);acquiredTiming;terminalTiming.Timing is observation metadata. It is excluded from ranking, selected digest,
catalog digest, and deterministic
selectionfields.#26 does not call
action. The monotonic acquisition token only allows afuture authorized same-process orchestrator to calculate quote-to-action
elapsed time. Clock/process discontinuity is unprovable; wall-clock subtraction
must not replace the monotonic calculation.
10. Closed failure vocabulary and precedence
QuoteCandidateFailureCodeV0_1is exactly:Global invalid request/catalog throws
MossAdapterError(INVALID_INPUT, quote)before candidate outcomes exist.
Per-candidate precedence is exactly:
PROTOCOL_NOT_ALLOWED;UNKNOWN_ASSET;UNKNOWN_DECIMALS;QUOTE_TIMEOUT;QUOTE_ACQUISITION_FAILED;MALFORMED_QUOTE;ASSET_DIRECTION_MISMATCH;AMOUNT_BASIS_MISMATCH;ELIGIBLE.Exactly one precedence result is retained per candidate. Later checks do not
overwrite an earlier failure.
An existing stable source
MossAdapterError.codeis retained only in theQUOTE_ACQUISITION_FAILEDbranch assourceErrorCode: MossAdapterErrorCode | null. Generic/hostile exceptionsproduce
null. No raw exception, cause, message, URL, headers, account,params, key, or source object is retained in that branch.
11. Exact correlated candidate outcome discriminated union
QuoteCandidateOutcomeV0_1is exported exactly as the following literalunion. The three
INELIGIBLEvariants are separate union members;rawandfailureare not independent unions.Correlation is therefore part of the exported TypeScript contract:
MALFORMED_QUOTEmay pair with eitherSNAPSHOTTEDorUNSNAPSHOTTABLEfromRawQuoteRetentionV0_1;ASSET_DIRECTION_MISMATCHcan pair only withSNAPSHOTTED;AMOUNT_BASIS_MISMATCHcan pair only withSNAPSHOTTED;ELIGIBLEcan pair only withSNAPSHOTTEDand must containnormalized;packages/moss-adapter/test/contracts.test.tsmust freeze compile-time evidence:snapshotted mismatch variants use
satisfies QuoteCandidateOutcomeV0_1;Extractplus anAssertNever<T extends never>assertion proves eachUNSNAPSHOTTABLEmismatch intersection isnever;UNSNAPSHOTTABLE + ASSET_DIRECTION_MISMATCHandUNSNAPSHOTTABLE + AMOUNT_BASIS_MISMATCHare each guarded by@ts-expect-error, and typecheck fails if either directive becomes unused.Runtime collector tests separately exercise malformed-snapshotted,
malformed-unsnapshottable, asset-mismatch-snapshotted, and
amount-mismatch-snapshotted outcomes and assert their exact keys. They also
assert that no produced asset/amount mismatch has
raw.status === "UNSNAPSHOTTABLE".Every candidate ProtocolId appears once. Outcomes are sorted by ProtocolId
UTF-8 byte order, not input or settlement order.
12. Normalized quote contract and lossless ranking
Every eligible candidate has exact request output-asset identity, so all output
amounts share one catalog decimals record. Normalization is lossless:
No division, multiplication, rounding, display unit, cross-asset conversion,
USD value, symbol, or Number is used. The maximum uint256 value is accepted.
Winner:
BigInt(normalizedAmountOut);TextEncoderand numeric byte comparison;localeCompare, collation, case folding, Unicode normalization,candidate order, settlement order, time, random value, or environment input.
ProtocolId is canonical lowercase ASCII, so its UTF-8 and ASCII bytes coincide.
13. Port change and exact timeout semantics
This v4 still requests a new Scope Gate for the disclosed, backward-compatible
optional signal expansion:
ProductionMossPort,FakeMossPort, andcreateBoundMossPortforwardthe exact signal. No other method changes. Existing two-argument calls remain
valid.
For each allowed, catalog-known candidate:
AbortController;port.quotecall;controller.abort("MOSS_MINI_DEMO_QUOTE_TIMEOUT_V0_1");QUOTE_TIMEOUToutcome;Promise.allSettled.Collector terminality is the local immutable state transition in step 5. It
does not depend on source cooperation.
Signal propagation guarantees only:
signal.aborted === trueafter deadline;signal.reason === "MOSS_MINI_DEMO_QUOTE_TIMEOUT_V0_1".#26 does not claim that the underlying source request was canceled. A
cooperative source may stop. A signal-ignoring source may still fulfill/reject
later; both paths are drained. Quote is required to be a read-only operation,
but this interface cannot prove absence of external effects in an unimplemented
real source.
No output or documentation may say “source canceled” or equivalent unless a
future concrete binding independently proves that behavior.
A bare
Promise.racewithout preattached late-settlement drainage isforbidden.
14. Exact selected digest and top-level result unions
SELECTEDexists only when exactly one outcome is the deterministic winner.The selected protocol references an
ELIGIBLEoutcome.NOT_SELECTEDexists only when zero outcomes are eligible. The full candidate list is always
present.
The selected digest payload is exactly:
It is passed to
canonicalize@3.0.0; canonical UTF-8 bytes are hashed oncewith Node
createHash("sha256"). Output issha256:plus exactly 64 lowercase hex characters.A canonicalization rejection, undefined result, invalid Unicode, or non-I-JSON
value yields
MALFORMED_QUOTE; no fallback serializer exists.The digest is only a deterministic fingerprint of selected Quote context. It
is not a signature, Capability digest, integrity proof, execution binding, or
evidence that a later Capability came from this Quote.
acquiredTiming,terminalTiming, candidate order, settlement order,deadline, and wall/monotonic time are excluded from catalog digest, selected
digest, ranking, and selected subobject.
15. Frozen RFC 8785 conformance vector with one canonical representation
The implementation and publication-readback tests use the exact public
values.jsonvector from the RFC 8785 reference test corpus:https://github.com/cyberphone/json-canonicalization/blob/master/testdata/input/values.json
https://github.com/cyberphone/json-canonicalization/blob/master/testdata/output/values.json
https://github.com/cyberphone/json-canonicalization/blob/master/testdata/outhex/values.txt
Exact reference input text, with U+000F represented by the literal six ASCII
characters \u000f:
{ "numbers": [333333333.33333329, 1E30, 4.50, 2e-3, 0.000000000000000000000000001], "string": "\u20ac$\u000f\u000aA'\u0042\u0022\u005c\\\"\/", "literals": [null, true, false] }Exact canonical output text, also with the literal six ASCII characters
\u000f and no caret notation:
{"literals":[null,true,false],"numbers":[333333333.3333333,1e+30,4.5,0.002,1e-27],"string":"€$\u000f\nA'B\"\\\\\"/"}Exact UTF-8 bytes of that canonical text, in lowercase hexadecimal:
The frozen canonical UTF-8 length is
118. Its SHA-256 is:2d5e01a318d0f0879ab568c4be289c8b1f64ef8921a53c6277d5e069978baacbThe required independent checks are:
JSON.parse(referenceInputText)succeeds;JSON.parse(expectedCanonicalText)succeeds;Buffer.from(expectedCanonicalText, "utf8")is 118 bytes;5c7530303066and equals the complete frozen vector;canonicalize@3.0.0(JSON.parse(referenceInputText))equalsexpectedCanonicalTextbyte-for-byte.Expected values are literal constants and are not regenerated from the
implementation under test. No actual U+000F byte, caret representation, or
competing golden text is accepted.
16. Frozen synthetic catalog and selected-Quote golden vectors
The test catalog source payload is exactly:
{ "schemaVersion": "moss-mini-demo/asset-catalog/0.1", "catalogId": "synthetic-assets", "sourceVersion": "1.0.0", "provenance": "SYNTHETIC_TEST", "sourceReference": "test/asset-catalog-v1", "chainId": 143, "validFrom": "2026-01-01T00:00:00.000Z", "validUntil": "2027-01-01T00:00:00.000Z", "entries": [ { "asset": { "kind": "ERC20", "address": "0x2222222222222222222222222222222222222222" }, "decimals": { "status": "KNOWN", "value": 6 } }, { "asset": { "kind": "NATIVE" }, "decimals": { "status": "KNOWN", "value": 18 } } ] }Expected canonical catalog text:
{"catalogId":"synthetic-assets","chainId":143,"entries":[{"asset":{"address":"0x2222222222222222222222222222222222222222","kind":"ERC20"},"decimals":{"status":"KNOWN","value":6}},{"asset":{"kind":"NATIVE"},"decimals":{"status":"KNOWN","value":18}}],"provenance":"SYNTHETIC_TEST","schemaVersion":"moss-mini-demo/asset-catalog/0.1","sourceReference":"test/asset-catalog-v1","sourceVersion":"1.0.0","validFrom":"2026-01-01T00:00:00.000Z","validUntil":"2027-01-01T00:00:00.000Z"}Expected catalog digest:
sha256:9f09d6a5e86f4ab1e459a7e0db1fd981afcbafe8cdc880e4e6b8e295dfc9a75eThe fixed selected-Quote digest payload is exactly:
{ "schemaVersion": "moss-mini-demo/selected-quote-digest/0.1", "chainId": 143, "protocolId": "alpha-protocol", "method": "swap", "account": "0x1111111111111111111111111111111111111111", "inputAsset": { "kind": "NATIVE" }, "outputAsset": { "kind": "ERC20", "address": "0x2222222222222222222222222222222222222222" }, "inputAmount": "1000000000000000000", "outputAmount": "42000000", "catalog": { "catalogId": "synthetic-assets", "sourceVersion": "1.0.0", "provenance": "SYNTHETIC_TEST", "sourceReference": "test/asset-catalog-v1", "digest": "sha256:9f09d6a5e86f4ab1e459a7e0db1fd981afcbafe8cdc880e4e6b8e295dfc9a75e" }, "inputDecimals": 18, "outputDecimals": 6, "observableBlockWindow": { "fromBlock": "100", "toBlock": "101" }, "mossSource": { "provenance": "SYNTHETIC_FAKE", "upstreamCommit": "1ae6b6322d51fae9104f047efb94e601050b967f", "integrationCommit": "1ae6b6322d51fae9104f047efb94e601050b967f", "patchsetDigest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "rawQuote": { "chainId": 143, "inputAsset": { "kind": "NATIVE" }, "outputAsset": { "kind": "ERC20", "address": "0x2222222222222222222222222222222222222222" }, "amountIn": "1000000000000000000", "amountOut": "42000000", "observableBlockWindow": { "fromBlock": "100", "toBlock": "101" }, "synthetic": true } }Expected canonical selected-Quote text:
{"account":"0x1111111111111111111111111111111111111111","catalog":{"catalogId":"synthetic-assets","digest":"sha256:9f09d6a5e86f4ab1e459a7e0db1fd981afcbafe8cdc880e4e6b8e295dfc9a75e","provenance":"SYNTHETIC_TEST","sourceReference":"test/asset-catalog-v1","sourceVersion":"1.0.0"},"chainId":143,"inputAmount":"1000000000000000000","inputAsset":{"kind":"NATIVE"},"inputDecimals":18,"method":"swap","mossSource":{"integrationCommit":"1ae6b6322d51fae9104f047efb94e601050b967f","patchsetDigest":"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","provenance":"SYNTHETIC_FAKE","upstreamCommit":"1ae6b6322d51fae9104f047efb94e601050b967f"},"observableBlockWindow":{"fromBlock":"100","toBlock":"101"},"outputAmount":"42000000","outputAsset":{"address":"0x2222222222222222222222222222222222222222","kind":"ERC20"},"outputDecimals":6,"protocolId":"alpha-protocol","rawQuote":{"amountIn":"1000000000000000000","amountOut":"42000000","chainId":143,"inputAsset":{"kind":"NATIVE"},"observableBlockWindow":{"fromBlock":"100","toBlock":"101"},"outputAsset":{"address":"0x2222222222222222222222222222222222222222","kind":"ERC20"},"synthetic":true},"schemaVersion":"moss-mini-demo/selected-quote-digest/0.1"}Expected selected-Quote digest:
sha256:b9ee24d4c1566c35b3282f4b15fc4d98551f4c2d199ea8221926bf09c8f37594Tests must compare the fixed payload, canonical text, and expected hash
literally. Recomputing expected values using the code under test is not
acceptance evidence.
All addresses, protocol IDs, times, amounts, block values, raw values, catalog
metadata, and provenance in these vectors are synthetic test data.
17. Complete deterministic selection and timeout test matrix
packages/moss-adapter/test/quote.test.tsmust cover:INVALID_INPUT and zero delegations;
SYNTHETIC_TEST;over-uint256 rejection;
MALFORMED_QUOTE;satisfiesexamples for every correlatedINELIGIBLEbranch;
AssertNeverand@ts-expect-errorevidence that both unsnapshottablemismatch combinations are forbidden by the exported type;
vector from Section 15;
digest, and selected digest.
packages/moss-adapter/test/selection.test.tsmust cover the following exactmatrix and expected discriminants:
ELIGIBLE, secondELIGIBLE,top
SELECTEDfirst;SELECTEDsecond;selected protocol, catalog digest, and selected digest;
SKIPPED/PROTOCOL_NOT_ALLOWED, zero call for it;SKIPPED/UNKNOWN_ASSET, zero Quote calls;SKIPPED/UNKNOWN_DECIMALS, zero Quote calls;ACQUISITION_FAILED/QUOTE_TIMEOUT;no mutation/selection pollution;
no unhandled rejection;
retained with safe sourceErrorCode/null;
INELIGIBLE, eligible selected;UNSNAPSHOTTABLE, no source leak;INELIGIBLE/ASSET_DIRECTION_MISMATCH;INELIGIBLE/AMOUNT_BASIS_MISMATCH;NOT_SELECTED/NO_ELIGIBLE_QUOTE;retained under its single precedence code;
and no input mutation.
The correlated-union runtime matrix additionally asserts:
INELIGIBLE/MALFORMED_QUOTE;INELIGIBLE/MALFORMED_QUOTE;INELIGIBLE/ASSET_DIRECTION_MISMATCHwithraw.status: "SNAPSHOTTED";INELIGIBLE/AMOUNT_BASIS_MISMATCHwithraw.status: "SNAPSHOTTED";UNSNAPSHOTTABLE.Additional regressions:
quotecalls remain valid;collectAndSelectQuotesV0_1;server-only;The aggregate must use
Promise.allSettled, retain one terminal outcome percandidate, and return byte-ordered frozen outcomes.
18. Implementation sequence after authorization
a0f3a3e8605812c9f0997059b4a30ea7a736022c.codex/issue-26-quote-selectionand the approved isolatedworktree.
changing the five-method port.
digest.
drainage, and
Promise.allSettled.selected digest.
source immutability, prohibited wording, and fixed vectors.
Closes #26, wait for exact-head CI, postImplementation Report and Pre-PR QA Handoff, then freeze the Head.
No implementation action occurs before a Maintainer explicitly accepts v4 with
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED.19. Local and CI verification
Use Node
22.23.1and pnpm11.16.0. Final evidence runs from a freshisolated checkout with no pre-existing
distor.next:node --version pnpm --version pnpm install --frozen-lockfile pnpm --filter @moss-mini-demo/moss-adapter build pnpm --filter @moss-mini-demo/moss-adapter typecheck pnpm vitest run packages/moss-adapter/test/quote.test.ts pnpm vitest run packages/moss-adapter/test/selection.test.ts pnpm vitest run packages/moss-adapter/test pnpm test:package-import pnpm build pnpm typecheck pnpm test pnpm check pnpm test:web:bundle pnpm test:web:production git diff --check origin/main...HEAD git diff --name-only origin/main...HEAD git status --shortAcceptance requires:
pass;
SHA, and equals
canonicalize@3.0.0output;mutation, late-promise mutation, unhandled rejection, or source-cancellation
overclaim;
quality-gateSUCCESS;20. Explicit non-goals
#26 does not implement:
claims;
behavior.
No ADR, workflow, docs, report-schema source, decision-engine, Fixture,
Issue/Project state, branch protection, required check, permission, main, Moss
gitlink, or
.gitmoduleschange is in scope.21. Risks, stop conditions, and rollback
Primary risks:
Stop and return to Maintainer if:
external mutation;
parameter;
seventeenth path, workflow, docs, ADR, Schema, Web/API, or vendor change is
needed;
RPC, wallet, signing, or transaction behavior.
Rollback is one revert of the #26 implementation commit after merge, or removal
of only the unmerged #26 branch/PR. It must not revert #25/#24, edit main
directly, change the Moss gitlink, or modify protection/required checks.
22. Requested Maintainer decision
Please record one of:
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED, explicitly accepting this v4comment, exact 16 paths, two dependencies, public API/unions, separate
catalog trust semantics, catalog digest/freshness, optional signal forwarding,
collector-only timeout claims, raw/normalized ownership, deterministic
selection, exact vectors, non-goals, and stop conditions; or
SCOPE_CHANGES_REQUESTED, naming the exact path, dependency, API, trust,evidence, vector, or semantic decision that must change.
Until that decision exists:
WORK_PLAN_V4_SUBMITTED / AWAITING_MAINTAINER_SCOPE_CONFIRMATIONNo implementation branch, worktree, file change, dependency installation,
lockfile generation, commit, push, or PR is authorized.
pillowtalk-Qy commentedon Aug 6, 2026
Work Plan v4 Publication Readback Verification - Maintainer Scope Review Requested
v1, v2, v3, and all review records remain unchanged. Please perform a new
Maintainer Scope Gate against the complete v4 comment.
Until an explicit SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED record exists:
WORK_PLAN_V4_SUBMITTED / AWAITING_MAINTAINER_SCOPE_CONFIRMATION
pillowtalk-Qy commentedon Aug 6, 2026
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED
Authorized planning object:
5201269230updated_at:2026-08-06T06:42:10Zf30f88dbe065a257a669d5c68e9f50abb7ae0495bd9232d7a69e5525a7322732origin/main@a0f3a3e8605812c9f0997059b4a30ea7a736022cMaintainer Scope Gate evidence:
JSON.parse; both decoded strings contain U+000F;2d5e01a318d0f0879ab568c4be289c8b1f64ef8921a53c6277d5e069978baacb;canonicalize@3.0.0(JSON.parse(referenceInputText))equals the expected canonical text byte-for-byte;INELIGIBLEmembers, making both unsnapshottable mismatch combinations unrepresentable;satisfies/AssertNever/@ts-expect-errorchecks and the correlated runtime matrix are required;@moss-mini-demo/report-schema: workspace:*andcanonicalize: 3.0.0; the existingserver-onlydependency remains unchanged;Implementation authorization:
codex/issue-26-quote-selectionin a new isolated worktree from the exact baseline above, after the old M2-04: Create moss-adapter package and public ports #25 execution environment is cleanly removed.@moss-mini-demo/moss-adapter; the only new runtime export iscollectAndSelectQuotesV0_1.This record authorizes only the frozen Work Plan v4 implementation scope. It is not QA PASS, Maintainer Review, READY_TO_MERGE, Merge Gate, or merge authorization.
pillowtalk-Qy commentedon Aug 6, 2026
EXECUTION_ENVIRONMENT_CLEARED
Post-authorization local handoff:
/Users/qy/Documents/moss-mini-demo-issue-25was clean at1b45d53e8307b579a6840b01e472f03d896867e3and has been removed;codex/issue-25-moss-adapter-portshas been deleted;codex/issue-26-quote-selectionbranch and no M2-05: Implement quote collection and deterministic selection #26 PR existed at this handoff;origin/main@a0f3a3e8605812c9f0997059b4a30ea7a736022c.Builder may now create a new isolated #26 worktree and the authorized
codex/issue-26-quote-selectionbranch from that exact baseline. The old #25 branch/worktree must not be reused. Iforigin/mainmoves before creation, stop and return for a refreshed Scope Gate.This handoff does not start QA, Review, READY_TO_MERGE, Merge Gate, or merge authorization.
pillowtalk-Qy commentedon Aug 6, 2026
SCOPE_AMENDMENT_CONFIRMED / PATH_17_IMPLEMENTATION_AUTHORIZED
Maintainer has independently inspected the current
main@a0f3a3e8605812c9f0997059b4a30ea7a736022cversion ofpackages/moss-adapter/test/server-only.test.ts.Decision: YES, the seventeenth path is authorized, subject to the exact closed boundary below.
Reason
Frozen Work Plan v4 already requires all of the following:
collectAndSelectQuotesV0_1;The existing
server-only.test.tsindependently asserts the complete approved runtime-export allowlist for the source entry. Adding the v4-required runtime export necessarily makes that unchanged allowlist fail. Therefore the original 16-path list omitted one pre-existing test that must be updated to express the already-approved public contract. This amendment corrects the writable-path list; it does not expand product behavior or change the v4 contract.Exact amendment
The authorized writable-path count changes from 16 to 17 by adding exactly:
packages/moss-adapter/test/server-only.test.tsWithin this seventeenth path, Builder may make exactly one semantic change:
"collectAndSelectQuotesV0_1"to the expected runtime-export array inkeeps the source entry limited to the approved runtime exports, preserving the array's default JavaScript sort order.The resulting expected runtime-export list must be exactly:
No test may be removed, skipped, weakened, renamed, mocked differently, or broadened. No server-only behavior, import condition, subprocess assertion, type-only export assertion, package export map, dependency, production code, or other line in this file may change except formatting strictly required by the one inserted array member.
Unchanged authority and stop conditions
Work Plan v4 comment
5201269230, frozen at2026-08-06T06:42:10Zwith body SHA-256f30f88dbe065a257a669d5c68e9f50abb7ae0495bd9232d7a69e5525a7322732, and the originalSCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZEDrecord remain authoritative in every other respect.This is a v4 scope-list correction, not a new API/version decision and not authorization for #27 behavior.
Any eighteenth path, second change in
server-only.test.ts, third dependency, extra runtime export, contract change, workflow change, root-script change, Web/API change, vendor change, or #27 behavior remains a stop condition requiring a new Maintainer decision.Required handoff evidence
The eventual Implementation Report / QA Handoff must include:
packages/moss-adapter/test/server-only.test.ts;This amendment authorizes Builder Qy to continue implementation and run the complete test matrix. It is not QA PASS, READY_TO_MERGE, Merge Gate, or merge authorization.
feat: collect and deterministically select quotes (#73)
pillowtalk-Qy commentedon Aug 6, 2026
POST_MERGE_AUDIT_PASS
Issue #26 delivery has completed on the exact authorized object.
97e2806d43caae1881adae9b1c620a2b79d8ce84main@a0f3a3e8605812c9f0997059b4a30ea7a736022c65753ada85156716e263b660eeab72c42d2934312026-08-06T13:34:05ZPost-merge audit:
quality-gate, resolved conversations, linear history, enforced admins, no force-push/delete, and Maintainers-only push restrictions;This audit completes Issue #26 only. It does not authorize Issue #27 implementation; #27 may enter planning only after its dependency-gate record and must receive a separate Work Plan Scope Gate before any implementation branch, commit, or PR.