Repository navigation
M1-03: Implement fail-closed decision engine #6
Copy link
Copy link
Closed
Labels
area:architectureArchitecture and module boundariesArchitecture and module boundariesarea:qaQuality assurance and testingQuality assurance and testingpriority:P0Critical priorityCritical priorityrisk:trust-boundaryChanges a trust or evidence boundaryChanges a trust or evidence boundarytype:featureNew product functionalityNew product functionality
Description
Fallback owner: Qy
Maintainer contract:
- ADR 0001 and ADR 0002 fix the PreflightReport v0.1 evidence contract.
- ADR 0003 fixes the Decision Engine v0.1 module, input, output, STOP reason-code, SourceReference, determinism, and test contracts.
- PR feat: add PreflightReport v0.1 runtime schema #15 is a delivery dependency only and is not a contract source.
Delivery dependency:
- Architecture planning and contract review are complete.
- Decision Engine business implementation must not begin until M1-02: Define PreflightReport v0.1 runtime schema #5 and its implementation PR feat: add PreflightReport v0.1 runtime schema #15 are merged to main and that main head passes quality-gate.
- After the dependency merges, implementation starts from latest main and the implementation PR remains Draft until its current-head quality-gate and Maintainer Review pass.
- Merge order remains controlled by Qy through the Merge Gate.
Scope:
- Create only @moss-mini-demo/decision-engine under the ADR 0003 package and public-entry boundary.
- Evaluate the validated DecisionInputV0_1 projection.
- Output only MANUAL_REVIEW or STOP with canonical structured reasons.
- Return all mandatory STOP reasons using the fixed code order and relevant raw SourceReferences.
- Remain pure, synchronous, deterministic, offline, and free of input mutation.
Acceptance:
- Implement the exhaustive ADR 0003 StopReasonCodeV0_1 table without additions or aliases.
- Every reason code has a positive trigger test.
- Every reason code rejects missing, dangling, unrelated, metadata-targeting, and circular references.
- Multiple reasons are complete, deduplicated, and ordered by canonical rank.
- Repeated triggers aggregate sorted unique SourceReferences.
- Invalid schema, unknown version, and invalid SourceReference reject before evaluation and emit no Decision.
- The exact MANUAL_REVIEW boundary passes only with all mandatory evidence available and favorable and all critical Alignment checks PASS.
- Any Warning, rollback, Receipt or Outcome failure, incomplete critical set, coverage failure, ordering failure, state interruption, critical Alignment FAIL/REVIEW, or missing/unprovable evidence produces STOP.
- Node 22 package-name import and complete offline Vitest matrix pass through the sole public entry.
- No test uses a network, real address, real protocol, or real-chain evidence.
Non-goals:
- No UI, protocol adapter, Moss, RPC, wallet, signing, transaction submission, persistence, risk score, natural-language safety claim, Fixture, or real-chain integration.
- No safe, approved, signable, or executable output.
- No change to MANUAL_REVIEW meaning, mandatory STOP conditions, raw-evidence ownership, or Capability integrity.
This Issue remains Open and Project Ready until actual dependency-cleared implementation begins.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:architectureArchitecture and module boundariesArchitecture and module boundariesarea:qaQuality assurance and testingQuality assurance and testingpriority:P0Critical priorityCritical priorityrisk:trust-boundaryChanges a trust or evidence boundaryChanges a trust or evidence boundarytype:featureNew product functionalityNew product functionality
Activity
docs: accept PreflightReport v0.1 schema contract (#13)
docs: freeze Decision Engine v0.1 contract (#17)
13 remaining items
pillowtalk-Qy commentedon Jul 31, 2026
Dependency gate cleared - 2026-07-31
Current implementation baseline:
main@27a9bc66f483a25d6602fdac2748099bfb32d67e.Evidence:
DecisionInputV0_1Schema, the fixed STOP enum, code-owned evidence references, canonicalitems/<i>paths, exact MANUAL_REVIEW shape, and the empty-collection-only v0.1 completeness boundary are runtime-enforced.Control decision:
Next required action:
@moss-mini-demo/decision-engineand the minimal approved stable-fact documentation updates.This record authorizes Ready status only. It does not approve an implementation diff or a Merge Gate conclusion.
pillowtalk-Qy commentedon Aug 2, 2026
Final Implementation Work Plan - Awaiting Maintainer Scope Confirmation
1. Planning authority, dependency gate, and exact baseline
This is a planning-only record for Issue #6. It does not start implementation.
Authoritative records checked:
Planning baseline: main@7bbbc8bb9b4acb859bc73ba2b861f657864cce5c
The exact baseline has a successful merged-main quality-gate:
https://github.com/Moss-Mini-Demo/moss-mini-demo/actions/runs/30752494660
Suggested future implementation branch:
No branch, worktree, file, commit, or PR was created for this planning task. Implementation may begin only after the Maintainer confirms this closed scope.
2. Closed future writable file list
The proposed implementation surface is exactly these 14 paths. There are no wildcard paths or open-ended directories.
No file below packages/report-schema is writable. No ADR, STOP presentation, Fixture, workflow, architecture, governance, security, UI, wallet, RPC, Moss, or Monad file is writable.
Separate Maintainer confirmation is requested for both root metadata files: package.json and pnpm-lock.yaml.
3. Package boundary and sole public API
Package identity:
Sole source entry:
Dependency direction:
Production code imports DecisionInputV0_1Schema and required TypeScript types only from the @moss-mini-demo/report-schema public package name. It will not import packages/report-schema/src or any private path.
The complete decision-engine public surface is limited to:
DecisionV0_1 and StopReasonCodeV0_1 are type-only aliases of the report-schema public types. The package will not export an internal rule, rank table, comparator, aggregation helper, parser helper, runtime Decision Schema, debug state, Result envelope, or report-schema runtime re-export.
No report-schema change is planned. Its existing public DecisionInputV0_1Schema and DecisionInputV0_1 type remain the sole runtime/type input contract.
4. Deterministic evaluation data flow
The evaluator will use this fixed synchronous flow:
A complete PreflightReport is rejected because decision and limitations are forbidden input fields. Invalid input produces no Decision and is never downgraded to STOP.
The Engine derives code-owned references only from the accepted ADR 0004 paths and validated alignment underlying references. It does not accept caller-authored Decision reasons and does not copy or repair invalid pointers.
5. Error classification and precedence
All boundary failures throw DecisionInputErrorV0_1. Its public readonly code is exactly one of:
Staged classification:
Classification uses structured issue paths, not Zod message text. DecisionInputErrorV0_1 exposes a stable code and stable code-derived message only; Zod text is not public contract data. No Result envelope, parser text, partial Decision, fallback Decision, or STOP is returned on an input error.
Tests will combine all class pairs and all three classes to prove precedence.
6. Exhaustive 22-code implementation and acceptance table
For every row, the positive test evaluates a valid synthetic input through @moss-mini-demo/decision-engine, asserts the exact code and references, assembles a synthetic report, and validates the association through the public PreflightReportSchema. The association-failure matrix described after the table runs for every code.
For ranks 120-122, component is exactly warnings, receipts, outcomes, coverage, ordering, or stateContinuity.
Available adverse evidence uses its semantic code and does not also become an availability code. One source may still produce multiple independently applicable codes, and all such codes remain present.
Per-code association-failure matrix:
Every mutation must be rejected by the public report-schema or DecisionInput boundary. Because the evaluator owns output references, it must never generate any of these invalid forms.
7. Aggregation, ordering, and no-mutation rules
Implementation invariants:
Tests deep-freeze input, take a deep copy before evaluation, compare after evaluation, repeat evaluation, reconstruct equivalent objects with different key insertion order, and assert deeply identical canonical output.
8. SourceReference rejection boundary
DecisionInputV0_1Schema remains the only runtime authority for pointer syntax, resolution, ownership, metadata exclusion, self-reference, and cycles. The Engine will not copy that Schema or implement a competing pointer validator.
Before rules run, tests must prove rejection of:
Raw payload keys whose names are sourceReferences, display, prose, extension, or extensions remain valid when structurally inside an accepted raw subtree. Natural language, metadata, an output Decision, limitations, or another reason can never prove a safety or STOP conclusion.
9. Exact MANUAL_REVIEW boundary
The only successful no-STOP output is exactly:
It has no reasons or other property.
The positive boundary requires all of the following:
Non-critical FAIL or REVIEW is not promoted into a new STOP semantic. MANUAL_REVIEW is human inspection only. It is not safety, approval, authorization, execution guarantee, signability, or permission to transact.
10. Closed test matrix
All decision-engine TypeScript tests import @moss-mini-demo/decision-engine by its public package name. Tests may use the public @moss-mini-demo/report-schema entry to construct types and validate assembled reports, but never import either package's private source.
Planned coverage:
Test data is synthetic and inline/test-constructor based. No Fixture file is added.
11. Minimal stable documentation update
README.md after implementation:
docs/real-vs-mock.md after implementation:
12. Future implementation verification
Required environment:
Commands:
The implementation PR must also obtain quality-gate SUCCESS for its exact current Head before Pre-PR QA or any Maintainer gate.
13. Explicit non-goals
14. Risks, rollback, and requested Maintainer confirmation
Risks to review before implementation:
Rollback is limited to the Maintainer reverting the future #6 independent implementation commit or squash merge. Schema or ADR changes are not a compensating rollback mechanism.
Maintainer scope confirmation is requested for:
Until that confirmation is recorded, no implementation branch, file, commit, or PR may be created.
15. Planning outcome
Requested status after this comment:
This comment does not enter Maintainer Review, Merge Gate, or implementation. Qy stops Builder activity after publishing and returns this plan to the independent Maintainer window.
pillowtalk-Qy commentedon Aug 2, 2026
SCOPE_CHANGES_REQUESTED
Scope Gate reviewed the fixed Final Work Plan at #6 (comment) against exact baseline
main@7bbbc8bb9b4acb859bc73ba2b861f657864cce5c, Accepted ADR 0003, and the corrections in Accepted ADR 0004. The baseline quality-gate is SUCCESS: https://github.com/Moss-Mini-Demo/moss-mini-demo/actions/runs/30752494660Contract result
The proposed pure, synchronous, offline, deterministic and fail-closed evaluator; strict public
DecisionInputV0_1Schemaboundary; three input error classes and precedence; exhaustive 22-code/rank/reference table; all-rule aggregation; UTF-8 reference ordering; exact{ "status": "MANUAL_REVIEW" }result; SourceReference ownership; public package dependency; 14-path boundary; runtime/type-only export boundary; and documentation/non-goal boundaries are consistent with ADR 0003 as corrected by ADR 0004. ADR 0004 correctly takes precedence for the MANUAL_REVIEW shape, canonicalitems/<i>paths, and empty-only Receipt/Outcome incompleteness.Blocking plan inconsistency
The closed plan does not yet provide an executable clean-checkout build/typecheck order for its required public package import:
.github/workflows/quality-gate.ymlperforms onlypnpm install --frozen-lockfileand thenpnpm check.checkrunstypecheckbeforebuild.@moss-mini-demo/report-schemapublishes its public type/runtime entry fromdist/index.d.tsanddist/index.js;distis not committed.package.jsonchange only to extendbuildandtest:package-import. Extendingbuildcannot make report-schemadistexist before the earlier clean-checkouttypecheck.pnpm --filter @moss-mini-demo/decision-engine buildbefore any explicit report-schema/root build, without defining how the public dependency has first been built.As written, the plan can therefore pass after a prior local build while still fail the required fresh-run quality-gate. Scope confirmation cannot rely on generated state left by an earlier command.
Required Work Plan revision
@moss-mini-demo/report-schemaimport. Do not importsrc, commitdist, build from test code, duplicate Schema validation, or add a third-party dependency.typecheck/checksemantics, adds a lifecycle script, changes workflow/config, or needs any path/operation beyond the fixed authorization request, state that expansion explicitly and request a new Maintainer Scope Gate. Do not hide it inside the existing build/smoke wording.Issue #6 remains Open / Qy assigned /
status:ready/ Project Ready / M1. Issues #8 and #20 remain Blocked.This is a planning Scope Gate only. It is not QA PASS, GitHub Review, Approval, Merge Gate, implementation authorization, or merge authorization.
pillowtalk-Qy commentedon Aug 2, 2026
Final Implementation Work Plan v2 - Clean Checkout Ordering Fixed - Awaiting Maintainer Scope Confirmation
1. Planning authority, dependency gate, and exact baseline
This is a planning-only record for Issue #6. It does not start implementation.
This v2 plan fully supersedes the earlier Work Plan at
#6 (comment)
without deleting or editing that historical comment. It resolves the
SCOPE_CHANGES_REQUESTED record at
#6 (comment)
and requests a new Maintainer Scope Gate.
Authoritative records checked:
Planning baseline: main@7bbbc8bb9b4acb859bc73ba2b861f657864cce5c
The exact baseline has a successful merged-main quality-gate:
https://github.com/Moss-Mini-Demo/moss-mini-demo/actions/runs/30752494660
Suggested future implementation branch:
No branch, worktree, file, commit, or PR was created for this planning task. Implementation may begin only after the Maintainer confirms this closed scope.
2. Closed future writable file list
The proposed implementation surface remains exactly the same 14 paths as v1: no path is added or removed. There are no wildcard paths or open-ended directories.
No file below packages/report-schema is writable. No ADR, STOP presentation, Fixture, workflow, architecture, governance, security, UI, wallet, RPC, Moss, or Monad file is writable.
Separate Maintainer confirmation is requested for both root metadata files: package.json and pnpm-lock.yaml.
3. Clean-checkout build and quality-gate ordering
The implementation must be verified from a newly created isolated worktree with
node_modules absent and every dist directory absent before installation. No
generated output from this planning workspace or another worktree may be reused.
The future root package.json script semantics are fixed as follows:
The executable one-line script values will use && between these steps so any
failure stops the quality gate. The current check order remains unchanged;
typecheck itself becomes responsible for preparing the report-schema public
types before root tsc runs. Root build then deterministically rebuilds
report-schema and builds decision-engine. test:package-import runs only after
both packages have been built by the preceding root build. test retains its
existing root-build precondition before Vitest.
The GitHub Actions workflow remains unchanged. Its only quality command remains:
The job name remains quality-gate, and its install step remains:
No prebuild, pretypecheck, prepare, postinstall, or other lifecycle script is
added. No TypeScript paths alias, committed dist, build invoked from test code,
third-party dependency, report-schema private import, or duplicated Schema is
allowed.
A clean checkout must not begin package verification with:
The normal clean-checkout command is pnpm build. If package-specific build
diagnosis is needed, the only valid explicit order is:
Production decision-engine TypeScript imports @moss-mini-demo/report-schema by
its public package name. Decision-engine Vitest files import only their package's
sole source entry, ../src/index.js, so root tsc does not require decision-engine
dist before the later build step. The Node 22 smoke test imports
@moss-mini-demo/decision-engine by package name only after root build has
created dist. No test imports input-boundary.ts or evaluate.ts directly.
4. Package boundary and sole public API
Package identity:
Sole source entry:
Dependency direction:
Production code imports DecisionInputV0_1Schema and required TypeScript types only from the @moss-mini-demo/report-schema public package name. It will not import packages/report-schema/src or any private path.
The complete decision-engine public surface is limited to:
DecisionV0_1 and StopReasonCodeV0_1 are type-only aliases of the report-schema public types. The package will not export an internal rule, rank table, comparator, aggregation helper, parser helper, runtime Decision Schema, debug state, Result envelope, or report-schema runtime re-export.
No report-schema change is planned. Its existing public DecisionInputV0_1Schema and DecisionInputV0_1 type remain the sole runtime/type input contract.
5. Deterministic evaluation data flow
The evaluator will use this fixed synchronous flow:
A complete PreflightReport is rejected because decision and limitations are forbidden input fields. Invalid input produces no Decision and is never downgraded to STOP.
The Engine derives code-owned references only from the accepted ADR 0004 paths and validated alignment underlying references. It does not accept caller-authored Decision reasons and does not copy or repair invalid pointers.
6. Error classification and precedence
All boundary failures throw DecisionInputErrorV0_1. Its public readonly code is exactly one of:
Staged classification:
Classification uses structured issue paths, not Zod message text. DecisionInputErrorV0_1 exposes a stable code and stable code-derived message only; Zod text is not public contract data. No Result envelope, parser text, partial Decision, fallback Decision, or STOP is returned on an input error.
Tests will combine all class pairs and all three classes to prove precedence.
7. Exhaustive 22-code implementation and acceptance table
For every row, the positive test evaluates a valid synthetic input through the decision-engine sole public entry, asserts the exact code and references, assembles a synthetic report, and validates the association through the public PreflightReportSchema. The association-failure matrix described after the table runs for every code.
For ranks 120-122, component is exactly warnings, receipts, outcomes, coverage, ordering, or stateContinuity.
Available adverse evidence uses its semantic code and does not also become an availability code. One source may still produce multiple independently applicable codes, and all such codes remain present.
Per-code association-failure matrix:
Every mutation must be rejected by the public report-schema or DecisionInput boundary. Because the evaluator owns output references, it must never generate any of these invalid forms.
8. Aggregation, ordering, and no-mutation rules
Implementation invariants:
Tests deep-freeze input, take a deep copy before evaluation, compare after evaluation, repeat evaluation, reconstruct equivalent objects with different key insertion order, and assert deeply identical canonical output.
9. SourceReference rejection boundary
DecisionInputV0_1Schema remains the only runtime authority for pointer syntax, resolution, ownership, metadata exclusion, self-reference, and cycles. The Engine will not copy that Schema or implement a competing pointer validator.
Before rules run, tests must prove rejection of:
Raw payload keys whose names are sourceReferences, display, prose, extension, or extensions remain valid when structurally inside an accepted raw subtree. Natural language, metadata, an output Decision, limitations, or another reason can never prove a safety or STOP conclusion.
10. Exact MANUAL_REVIEW boundary
The only successful no-STOP output is exactly:
It has no reasons or other property.
The positive boundary requires all of the following:
Non-critical FAIL or REVIEW is not promoted into a new STOP semantic. MANUAL_REVIEW is human inspection only. It is not safety, approval, authorization, execution guarantee, signability, or permission to transact.
11. Closed test matrix
All decision-engine Vitest files import only the sole public source entry at ../src/index.js; they never import input-boundary.ts, evaluate.ts, or report-schema private source. Tests may use the public @moss-mini-demo/report-schema package entry to construct types and validate assembled reports. After root build, public-entry.smoke.mjs separately proves Node 22 package-name resolution for @moss-mini-demo/decision-engine.
Planned coverage:
Test data is synthetic and inline/test-constructor based. No Fixture file is added.
12. Minimal stable documentation update
README.md after implementation:
docs/real-vs-mock.md after implementation:
13. Future implementation verification
Required environment:
The verification must start in a new isolated worktree with no node_modules and
no dist directories. Record that precondition, then run exactly:
A standalone pnpm typecheck must pass immediately after frozen install because
it builds report-schema before root tsc. pnpm build must then build
report-schema before decision-engine. Both Node 22 public package-name smoke
tests must pass after that build. pnpm check is the same entry used by GitHub
Actions and must pass from the same clean-checkout state.
The implementation PR must also obtain quality-gate SUCCESS for its exact current Head before Pre-PR QA or any Maintainer gate.
14. Explicit non-goals
15. Risks, rollback, and requested Maintainer confirmation
Risks to review before implementation:
Rollback is limited to the Maintainer reverting the future #6 independent implementation commit or squash merge. Schema or ADR changes are not a compensating rollback mechanism.
Maintainer scope confirmation is requested for:
Until that confirmation is recorded, no implementation branch, file, commit, or PR may be created.
16. Planning outcome
Requested status after this comment:
This v2 comment requests a new Maintainer Scope Gate. It does not claim SCOPE_CONFIRMED or IMPLEMENTATION_AUTHORIZED, and it does not enter Maintainer Review, Merge Gate, or implementation. Qy stops Builder activity after publishing and returns this plan to the independent Maintainer window.
pillowtalk-Qy commentedon Aug 2, 2026
SCOPE_CONFIRMED / IMPLEMENTATION_AUTHORIZED
Reviewed Work Plan v2:
#6 (comment)
Implementation authorized from
main@7bbbc8bb9b4acb859bc73ba2b861f657864cce5c.Approved:
package.jsonclean-checkout typecheck/build/test ordering;pnpm-lock.yamlworkspace importer/link only;evaluateDecisionV0_1andDecisionInputErrorV0_1runtime API;DecisionV0_1andStopReasonCodeV0_1type-only exports;README.mdanddocs/real-vs-mock.mdstable-fact updates.Writable paths, exactly:
package.jsonpnpm-lock.yamlpackages/decision-engine/package.jsonpackages/decision-engine/tsconfig.build.jsonpackages/decision-engine/src/index.tspackages/decision-engine/src/input-boundary.tspackages/decision-engine/src/evaluate.tspackages/decision-engine/test/synthetic.tspackages/decision-engine/test/input-boundary.test.tspackages/decision-engine/test/stop-reason-matrix.test.tspackages/decision-engine/test/evaluate.test.tspackages/decision-engine/test/public-entry.smoke.mjsREADME.mddocs/real-vs-mock.mdpackage.jsonapproval is limited to: build report-schema before root typecheck; build report-schema then decision-engine; run both public-entry smoke tests; retain root-build-before-Vitest; keepcheckas the sole unchanged-stage quality-gate entry. No lifecycle script, workflow change, private-source path alias, test-hidden build, committeddist, or dependency change is authorized.pnpm-lock.yamlapproval is limited to the newpackages/decision-engineworkspace importer and its workspace link to@moss-mini-demo/report-schema; no third-party package or unrelated lockfile change is authorized.ADR 0004 governs its corrections to ADR 0003.
Any additional file, dependency, export, Schema/ADR change, workflow change, Fixture, product integration, or trust-boundary change requires a new Maintainer Scope Gate.
This is implementation-scope authorization only. It is not QA PASS, GitHub Approval, READY_TO_MERGE, Merge Gate, or merge authorization.
pillowtalk-Qy commentedon Aug 3, 2026
POST_MERGE_GATE_BLOCKED
The post-merge dependency-release audit stopped. The required merged-main gate has not occurred.
5d4731985beb86281610ca7abf187287e5b1d8a0main@7bbbc8bb9b4acb859bc73ba2b861f657864cce5c7bbbc8bb9b4acb859bc73ba2b861f657864cce5ccodex/issue-6-decision-engine-v0-1still exists at the observed headRequired condition not met: PR #66 must first receive its exact-head Maintainer Merge Gate, be squash merged, and produce a SUCCESS quality-gate on the resulting main commit. Until then, #8 and #20 are not released and #9 remains blocked.
Control-plane result: #8, #20, and #9 remain Open /
status:blocked/ Project Blocked. No downstream assignee, claim, branch, worktree, implementation, Review, Merge Gate, or merge is authorized by this record.M1-03: implement fail-closed Decision Engine v0.1 (#66)
pillowtalk-Qy commentedon Aug 3, 2026
POST_MERGE_AUDIT
25f895cd2a1278bd864670afbe4b0f735dc62c2bmain@7bbbc8bb9b4acb859bc73ba2b861f657864cce5caa7ea761b2ac5e78535387e0a7d04d45485cdfb12026-08-03T16:43:56Z7bbbc8bb9b4acb859bc73ba2b861f657864cce5cquality-gate, strict up-to-date, conversation resolution, linear history, enforce admins, no force-push/delete, and Maintainers Team push restriction remain enabledPR #66 and Issue #6 are archived as Project Done. The merge used the exact-head squash endpoint. No auto-merge or admin bypass was used, and no protection or permission setting was changed.
This audit completes Issue #6 only. It does not authorize or start #8, #20, or #9.
M1-05: add tokenOut mismatch STOP fixture (#67)