DEM-PLACEHOLDER-GUARD (core): the terminal guard — a placeholder can never come back - #39
Merged
Merged
Conversation
…eralize the composer DEM-GOV §9 DEM-PRODUCER-PLAN (owner-authorized 2026-08-25; afi-governance #55): the planned R:R is a PROVIDER fact the technical lane produces from the submitted afi.trade-plan.v1 and the registered mapping binds — never synthesized from analyst inputs again. - froggy.enrichment_adapter.ts: the synthesis at the old :282-283 is deleted; the builder returns FroggyAdapterOutput (Omit<…,'rrMultiplePlanned'>); the view type gains technical.plan (the lane's verified plan facts, read only through the mapping). - froggy.residual_builder.ts: residual Pick shrinks to the five still- unexpressible fields; the composer is mapping-version-agnostic and fail-closed — fragment ∪ residual must partition the ten scorer-input fields exactly and every value must lie in its declared domain (predicate-valued table: no scorer-input field is ever assigned a literal here). - froggy.trend_pullback_v1.ts: scoreFroggyTrendPullbackFromEnriched (the adapter-only convenience path) is deleted — the adapter no longer emits a full input; the rubric no longer imports the adapter. - tests: the registered 1.1.0 mapping as shared test data (inline, drift- checked against the sibling registry file when present); the residual builder suite proves compose(fragment, residual) == adapter output + the mapping-bound R:R (fired default recorded when the producer emitted none); composer refusal cases (missing / extra / dual-source / out-of-domain). No scoring-law value moves. afi-core suite 312/312. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ed literal DEM-GOV §9 DEM-PRODUCER-CANDLE (owner-authorized 2026-08-25; afi-governance #55) — the act D5-GOV D-D5-1 reserved. Merge after dem/plan-core, and after the reactor's PLAN wave has merged. - froggy.enrichment_adapter.ts: BROKE_EMA_WITH_BODY_UNIMPLEMENTED_STUB and its ?? read are DELETED, as is the `haFlatBackConfirmed: false` literal. Both are now computed technical-lane facts the registered mapping binds (required). FroggyAdapterOutput drops them; the view type gains the lane's brokeEmaWithBody / haFlatBack / haFlatBackConfirmed facts. - froggy.residual_builder.ts: the residual Pick shrinks to the HTF bias placeholders + liquiditySwept — three fields. - tests: mapping 1.2.0 in the shared support module (required binds); probes carry the candle facts and vary them; a view WITHOUT them now REFUSES at the interpreter (required-source-absent) instead of taking a stub — pinned in both the residual-builder and adapter suites. afi-core 313/313. No scoring-law value moves. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e "unknown" branch
DEM-GOV §9 DEM-PRODUCER-HTF (owner-authorized 2026-08-25; afi-governance #55)
— the mission DIR-GOV D-DIR-3's scope-guard reserved. Merge after the CANDLE
wave.
- froggy.enrichment_adapter.ts: the `weeklyBias = "neutral" as const` and
`dailyBias = "neutral" as const` literals are DELETED. Both are now computed
technical-lane facts (higher-timeframe trend) that the registered mapping
RECODES into the rubric's bias vocabulary. The view type gains technical.htf
{daily,weekly}. NOTHING this builder returns is a placeholder any more.
- froggy.residual_builder.ts: the residual is now ONE field, liquiditySwept —
the two-lane read D-DEM-3(5) expressly reserves. The D-DEM-4(2) placeholder
inventory is EMPTY.
- froggy.trend_pullback_v1.ts: the "unknown"-direction branch semantics are
RESOLVED as DIR-GOV's scope-guard requires (they could not be settled while
both biases were hardcoded and the branch unreachable): with real HTF facts
the four cases are exhaustive — long/short when both timeframes agree,
neutral when either has no directional bias, and "unknown" when both are
directional and DISAGREE (a higher-timeframe CONFLICT: the analyst declining
to call a direction, not an error and not an absence). It feeds no axis and
never reaches scoredSignal.direction. No code changed — the branch is
documented and pinned.
- tests: mapping 1.3.0 in the shared support (the bullish->long / bearish->short
/ range->neutral vocabulary translation lives in the MAPPING, never in the
producer, D-DEM-3); probes for aligned / conflicting / range / absent-window
HTF; five new direction-verdict tests including the conflict branch and a
proof that the verdict moves no axis.
afi-core 322/322. No scoring-law value moves.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…never come back DEM-GOV §9 DEM-PLACEHOLDER-GUARD (owner-authorized 2026-08-25; afi-governance #55), enforcing D-DEM-4(5). Merge last, after all three producer waves. - validators/PlaceholderLiteralGuard.ts (NEW): reads the field set from the FroggyTrendPullbackInput interface itself (so it can never drift from the rubric's contract) and flags any assignment to one of those field names whose value is a compile-time constant. Constancy is decided by the TYPE CHECKER as well as the syntax tree, so the exact retired form — a constant imported ACROSS a package boundary, whose initializer lives in another repo's .d.ts — is caught; a syntax-only guard cannot see it. Forms covered: literals, `as const`, unary of a literal, substitution-free templates, `x ?? CONST`, conditionals between constants, variable declarations, shorthand properties, and assignment expressions. The `typescript` API is imported LAZILY, so the published module is inert unless a test invokes it. - Exemptions are exactly the accepted text's: `liquiditySwept` (the reserved two-lane computation, D-DEM-3(5)); test directories; and a registered mapping's declared `default` literals — pinned to the REGISTERED VALUES, so the two D-DEM-5(4) grandfathers the retired adapter still applies (its physical deletion is reserved by DEM-BIND ruling R1) cannot drift from the document, and ANY other literal at the same site still fires. A synthesis is caught even when one arm equals a registered default. - test/guardrails/placeholderLiteralGuard.test.ts (NEW, 17 tests): the tree is CLEAN; six negative tests prove the guard bites on every retired form, including the cross-package one; five exemption tests prove it does not fire on mapping-sourced values, a mapping document's own literals, liquiditySwept, test fixtures, or the composer's predicate table. Zero scored-value movement by this slot. afi-core 339/339. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Kilo Code Review could not run — your account is out of credits. Add credits or switch to a free model to enable reviews on this change. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Wave 4 of 4 —
DEM-PLACEHOLDER-GUARD, step 1 of 2. Merge after all three producer waves. This is where it's finished.The accepted row and gate
How it decides
The field set is read from the
FroggyTrendPullbackInputinterface itself, so the guard can never drift from the rubric's contract. A finding is an assignment to one of those field names whose value is a compile-time constant — and constancy is decided by the type checker, not only the syntax tree.That last point is the whole reason this works. The retired stub at
laneView.ts:79was an identifier imported from another package, whose initializer lives in a.d.ts. A syntax-only scan cannot see that it is constant. The negative tests reconstruct exactly that form and prove the guard catches it, with the finding's reason naming the literal type.Forms covered: literals,
as const, unary of a literal, substitution-free templates,x ?? CONST, conditionals between constants, variable declarations, shorthand properties, assignment expressions.The exemptions are exactly the ones the accepted text states — and no wider
liquiditySwept— the reserved two-lane computation (D-DEM-3(5)).defaultliterals — pinned to the registered values, read from the document itself. So the two D-DEM-5(4) grandfathers the retired adapter still applies (its physical deletion is reserved by DEM-BIND ruling R1) cannot drift from the registered document, and any other literal at the same site still fires. A synthesis is caught even when one of its arms equals a registered default.17 tests: the tree is clean; six negatives prove the guard bites on every retired form; five exemption tests prove it does not fire where the text says it must not.
typescriptis imported lazily, so the published module is inert unless a test invokes it. Zero scored-value movement.🤖 Generated with Claude Code