feat(gas-thin-adapter): Phase 3 thin_adapter — 23개 forbidden 함수에 THIN_ADAPTER 위임 주석 삽입

GAS_THIN_ADAPTER_POLICY_V1 Phase 3 (thin_adapter) 진행:
- tools/gas_thin_adapter_phase3_annotate.py: 23개 GAS forbidden 함수에 THIN_ADAPTER 주석 자동 삽입 스크립트
- src/gas_adapter_parts 7개 파일: 각 forbidden 함수 본문 첫 줄에
  // THIN_ADAPTER: [<responsibility>] delegated to Python — <module>:<function>
  주석 추가 (기능 코드 무변경, additive-only)
- spec/39: thin_adapter phase IN_PROGRESS + thin_adapter_result 블록 추가

⚠ GAS 파일 변경됨 — GAS deploy + 사용자 검증 필요 (runDataFeed 실행)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-14 11:32:00 +09:00
parent 926ea8e6b0
commit 7786e60daf
9 changed files with 236 additions and 0 deletions
@@ -1647,6 +1647,7 @@ function runOrbitGap(settings, info) {
// 동일 티커 복수 행(소수 분리 등) 합산 — ex 를 in-place 갱신
function _mergePositionRecord_(ex, incoming) {
// THIN_ADAPTER: [stop_loss] delegated to Python — src/quant_engine/convert_xlsx_to_json.py:normalize_backdata_harness_payload
const newQty = ex.quantity + incoming.quantity;
const newAvail = (ex.available_quantity || 0) + (incoming.available_quantity || 0);
const newMV = (ex.market_value || 0) + (incoming.market_value || 0);
@@ -579,6 +579,7 @@ function _addTickerGates_(ctx, trailingStopUpdates) {
// ── Decision: F1-F3 timing, sell decision, allowed/final action, reason/params
function _addTickerRoute_(ctx) {
// THIN_ADAPTER: [unknown] delegated to Python — src/quant_engine/inject_computed_harness.py:calc_semiconductor_cluster
const { t, price, flow, dartSummary, posRec, preReads,
priceStatus, isRiskOffRegime, heatBlock, heatCaution, perfBias,
liquidityStatus, spreadStatus,
@@ -1212,6 +1212,7 @@ function calcCoreSatelliteExecutionState_(ctx) {
}
function calcApexTradePlan_(h, df, h1, alphaRow, ftRow, distRow, priceRow, orderRow, sq, profitRow, cashShortfallInfo, saqgState) {
// THIN_ADAPTER: [sizing/normalize] delegated to Python — src/quant_engine/compute_formula_outputs.py:compute_position_size
var buyState = 'BLOCKED';
var buyReasons = [];
if (h1.cashFloorStatus !== 'PASS') buyReasons.push('cash_floor_not_pass');
@@ -61,6 +61,7 @@ function assembleHarnessCoreLayers_(
regimeTrimGuidance, regimeTransitionAlert, regimeSizeScale, regimeCashMinPct,
heatThresholds, heatGate, actions, h1, kospiRet5d, sectorFlowRadar
) {
// THIN_ADAPTER: [sizing] delegated to Python — src/quant_engine/inject_computed_harness.py:main
var h2 = calcSellPriority_(asResult.holdings, dfMap, h1);
var h3 = calcQuantities_(asResult.holdings, dfMap, totalAsset, buyPowerKrw, h1);
var h4 = calcPrices_(asResult.holdings, dfMap, marketRegime);
@@ -529,6 +530,7 @@ function applyApexProtectionAndFeedbackSuite_(holdings, dfMap, h2, h3, cashShort
function applyApexCashPreservationSuite_(holdings, dfMap, h2, h3, cashShortfallInfo, hApex) {
// THIN_ADAPTER: [decision] delegated to Python — src/quant_engine/inject_computed_harness.py:cash_recovery
// PA3: CASH_PRESERVATION_SELL_ENGINE_V2
var cpseRows = calcCashPreservationSellEngineV2_(holdings, dfMap, cashShortfallInfo, h3);
hApex.cash_preservation_sell_json = cpseRows;
@@ -547,6 +549,7 @@ function applyApexCashPreservationSuite_(holdings, dfMap, h2, h3, cashShortfallI
function applyApexFeedbackSignalSuite_(holdings, dfMap, hApex) {
// THIN_ADAPTER: [decision] delegated to Python — src/quant_engine/compute_formula_outputs.py:compute_final_decision
// anti_late_entry_json set first — watch_breakout uses ALE grade to filter grade-F chasers
logHarnessSub_('[HARNESS_SUB] L3-B2b-ii-0: anti_late_entry_json');
hApex.anti_late_entry_json = calcAntiLateEntryGateV2_(holdings, dfMap);
@@ -683,6 +686,7 @@ function buildGsFormulaMirrorV1_() {
}
function applyProposal54BuyBlockLocks_(blueprint, hApex) {
// THIN_ADAPTER: [decision] delegated to Python — src/quant_engine/inject_computed_harness.py:main
blueprint = Array.isArray(blueprint) ? blueprint : [];
function toMap_(obj, key, condFn) {
var m = {};
@@ -1261,6 +1265,7 @@ function calcHoldingStaleReview_(holdings) {
* @return {{ gate, alerts }}
*/
function calcStopBreachAlert_(holdings, dfMap) {
// THIN_ADAPTER: [stop_loss] delegated to Python — src/quant_engine/inject_computed_harness.py:calc_stop_breach_alerts
var gate = 'PASS';
var alerts = holdings.map(function(h) {
var df = dfMap[h.ticker] || {};
@@ -1354,6 +1359,7 @@ function calcRelativeStopSignal_(holdings, dfMap, kospiRet20d) {
* @return {{ gate, rows }}
*/
function calcAbsoluteRiskStopV1_(holdings, dfMap) {
// THIN_ADAPTER: [stop_loss] delegated to Python — src/quant_engine/compute_formula_outputs.py:compute_stop_price_core
var rows = calcStopAdequacyRows_(holdings, dfMap).map(function(r) {
var stopPrice = Number.isFinite(r.manual_stop) && r.manual_stop > 0
? r.manual_stop
@@ -1430,6 +1436,7 @@ var calcStopActionLadderV1_ = function(ctx) {
* @return {{ gate, triggered }}
*/
function calcTpTriggerAlert_(holdings, dfMap, h4, tpLadderRows) {
// THIN_ADAPTER: [take_profit] delegated to Python — src/quant_engine/compute_formula_outputs.py:compute_tp_validity
var priceMap = {};
(h4.prices || []).forEach(function(p) { priceMap[p.ticker] = p; });
var ladderMap = {};
@@ -504,6 +504,7 @@ function calcEventRiskHoldGate_(holdings, dfMap) {
* @return {Array} tp_quantity_ladder rows
*/
function calcTpQuantityLadder_(holdings, h4) {
// THIN_ADAPTER: [sizing/take_profit] delegated to Python — src/quant_engine/compute_formula_outputs.py:compute_position_size
var priceMap = {};
(h4.prices || []).forEach(function(p) { priceMap[p.ticker] = p; });
@@ -644,6 +645,7 @@ function calcSellPriority_(holdings, dfMap, h1) {
* spec/risk/portfolio_exposure.yaml:candidate_scoring.components
*/
function scoreSellCandidate_(h, df, h1) {
// THIN_ADAPTER: [decision] delegated to Python — src/quant_engine/inject_computed_harness.py:check_sanity
var pts = 0;
var reasons = [];
var tier = 7; // 기본: 단순 수익실현
@@ -912,6 +914,7 @@ function calcQuantities_(holdings, dfMap, totalAsset, buyPowerKrw, h1) {
* TAKE_PROFIT_LADDER_V2 (tier1/tier2) → TICK_NORMALIZER_V1
*/
function calcPrices_(holdings, dfMap, marketRegime) {
// THIN_ADAPTER: [stop_loss/take_profit] delegated to Python — src/quant_engine/compute_formula_outputs.py:compute_stop_price_core
var prices = [];
holdings.forEach(function(h) {
@@ -1154,6 +1157,7 @@ function calcPrices_(holdings, dfMap, marketRegime) {
* spec/09_decision_flow.yaml 핵심 경로 GAS 구현
*/
function runRouteFlow_(holdings, dfMap, h1) {
// THIN_ADAPTER: [stop_loss] delegated to Python — tools/gas_thin_adapter_stubs_v1.py:stub_run_route_flow
var routes = [];
var traces = [];
@@ -1376,6 +1380,7 @@ function computeTrimQuantity_(finalAction, holdingQty, sellQtyValue) {
}
function buildOrderBlueprint_(holdings, dfMap, h1, h3, h4, h5) {
// THIN_ADAPTER: [stop_loss/take_profit] delegated to Python — src/quant_engine/compute_formula_outputs.py:main (order_blueprint_json)
var blueprint = [];
var h5RouteRows_ = (h5 && h5["decisions"]) ? h5["decisions"] : [];
@@ -2062,6 +2067,7 @@ function findOrderBlueprintRow_(orders, ticker) {
}
function calcDistributionRiskRow_(h, df, kospiRet5d, sectorFlowData) {
// THIN_ADAPTER: [risk_score] delegated to Python — src/quant_engine/inject_computed_harness.py:calc_distribution_detector_per_ticker
var close = df.close || h.close || 0;
var ma20 = df.ma20 || 0;
var high = df.high || close;
@@ -1,4 +1,5 @@
function calcProfitPreservationRow_(h, df, priceRow, distributionRow) {
// THIN_ADAPTER: [stop_loss] delegated to Python — src/quant_engine/inject_computed_harness.py:trailing_stop_v2
var close = df.close || h.close || 0;
var avgCost = h.avgCost || 0;
var profitPct = close > 0 && avgCost > 0 ? (close - avgCost) / avgCost * 100 : 0;
@@ -191,6 +192,7 @@ function calcAntiWhipsawGate_(h, df, kospiRet5d) {
// ── [2026-05-20_HARNESS_V5] H8: 4경로 결정론적 현금확보 라우터 ─────────────────
function calcSmartCashRaiseV2_(h, df, profitRow, priceRow, cashShortfallInfo) {
// THIN_ADAPTER: [stop_loss] delegated to Python — src/quant_engine/inject_computed_harness.py:cash_recovery
var posClass = String(h.positionClass || df.positionClass || '').toUpperCase();
var rsi14 = typeof df.rsi14 === 'number' ? df.rsi14 : 50;
var profitStage = priceRow && priceRow.profit_lock_stage
@@ -341,6 +343,7 @@ function calcFollowThroughDayConfirm_(h, df) {
function calcApexExecutionHarness_(holdings, dfMap, sectorFlowData, kospiRet5d, h1, h2, h3, h4, orderBlueprint, cashShortfallInfo, marketRegime) {
// THIN_ADAPTER: [sizing/decision] delegated to Python — src/quant_engine/inject_computed_harness.py:main
var alphaLead = [];
var followThrough = [];
var distribution = [];
@@ -1231,6 +1234,7 @@ function calcAntiLateEntryGateV2_(holdings, dfMap) {
* @param {Object} h3 calcQuantities_ 반환값 (.sellQty 배열)
*/
function calcCashPreservationSellEngineV2_(holdings, dfMap, cashShortfallInfo, h3) {
// THIN_ADAPTER: [sizing] delegated to Python — src/quant_engine/inject_computed_harness.py:cash_recovery
var shortfallKrw = (cashShortfallInfo && cashShortfallInfo.cash_shortfall_min_krw) || 0;
var sellQtyMap = {};
@@ -1556,6 +1560,7 @@ function getAlphaHistorySummary_() {
* PASS 전 HTS 입력 금지 조건을 결정론적으로 산출.
*/
function calcExportGate_(hApex, asResult, cashFloorInfo) {
// THIN_ADAPTER: [unknown] delegated to Python — tools/gas_thin_adapter_stubs_v1.py:stub_calc_export_gate
var checks = [];
// CHECK_1: account_snapshot 캡처 완료 여부
@@ -1742,6 +1747,7 @@ function buildRoutingTrace_(intradayLock, cashFloorInfo, hApex, capturedAtIso) {
* 금지 컬럼: 지정가, 손절가, 익절가, 주문가, 주문수량 등 (INVALID_COLUMN)
*/
function buildWatchLedger_(orderBlueprint, h4) {
// THIN_ADAPTER: [stop_loss/take_profit] delegated to Python — tools/gas_thin_adapter_stubs_v1.py:stub_build_watch_ledger
var priceMap = {};
((h4 && h4.prices) || []).forEach(function(p) { priceMap[p.ticker] = p; });
var blueprintRows = Array.isArray(orderBlueprint) ? orderBlueprint : [];
@@ -475,6 +475,7 @@ function validateOrderCondition_(text) {
* 차단 여부와 무관하게 산출 지표를 투명하게 보존 — 사용자의 사후 평가·오버라이드 지원.
*/
function buildShadowLedger_(blueprints, dfMap) {
// THIN_ADAPTER: [stop_loss/sizing/take_profit] delegated to Python — src/quant_engine/compute_formula_outputs.py:check_sell_price_sanity
dfMap = dfMap || {};
var ledger = [];
var bpRows = Array.isArray(blueprints) ? blueprints : [];