G0~G8 성과·동맹 측정 OS 작업 일괄 고정
8월 7일까지 워킹트리에만 남아 있던 미커밋 작업을 커밋한다. 여러 사본 폴더(worktree·clone)에 흩어져 있던 중간 스냅샷을 정리하기 전에 원본을 git 이력으로 고정하는 것이 목적이다. - contracts/routes/services: measurement, outcome_trajectory, rupture_repair, deliberate_practice, calibration_transfer, supervision_research, multimodal_alliance, continuous_improvement 계열 신규 모듈과 테스트 - infra/db/init: 07~16 마이그레이션(측정 기반~calibration transfer 실행) - apps/web: 세션 리뷰 카드·관리 화면·E2E 스펙 추가 - docs/ops: G0~G8 라이브 통합·배포·롤백 증거 문서와 evidence JSON/PNG - scripts: smoke·ledger·릴리스 에이전트·NAS 프리뷰 운영 스크립트 engine.public 로그 .bak과 apps/web/test-results 산출물은 커밋에서 제외했다.
This commit is contained in:
parent
93dd8f82d7
commit
16e791e044
390 changed files with 243188 additions and 499 deletions
189
scripts/check-measurement-ledger.sql
Normal file
189
scripts/check-measurement-ledger.sql
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
\set ON_ERROR_STOP on
|
||||
\if :{?app_role}
|
||||
\else
|
||||
\set app_role vignette_app
|
||||
\endif
|
||||
|
||||
-- Outcome & Alliance OS G0 live DB proof.
|
||||
-- Owner/superuser connection에서 실행하며 모든 fixture는 마지막에 rollback한다.
|
||||
|
||||
BEGIN;
|
||||
|
||||
INSERT INTO app.app_user (
|
||||
user_id, external_id, email, display_name, role, cohort, consent_at
|
||||
) VALUES (
|
||||
'a0000000-0000-4000-8000-000000000001',
|
||||
'dev:measurement-ledger-smoke',
|
||||
'measurement-ledger-smoke@example.invalid',
|
||||
'측정 원장 스모크',
|
||||
'learner',
|
||||
'measurement-smoke',
|
||||
now()
|
||||
)
|
||||
ON CONFLICT (user_id) DO NOTHING;
|
||||
|
||||
INSERT INTO app.sessions (
|
||||
id, learner_id, session_no, theory_mode
|
||||
) VALUES (
|
||||
'a0000000-0000-4000-8000-000000000002',
|
||||
'a0000000-0000-4000-8000-000000000001',
|
||||
1,
|
||||
'integrative'
|
||||
)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
INSERT INTO audit.model_run (
|
||||
model_run_id, session_id, agent_role, provider, model,
|
||||
prompt_bundle_id, prompt_bundle_version, prompt_bundle_hash,
|
||||
structured_schema_version, input_evidence_hash, status
|
||||
) VALUES
|
||||
(
|
||||
'a0000000-0000-4000-8000-000000000010',
|
||||
'a0000000-0000-4000-8000-000000000002',
|
||||
'evaluator', 'contract-smoke', 'deterministic',
|
||||
'measurement-smoke-evaluator', '1.0.0', repeat('a', 64),
|
||||
'measurement-event.v1', repeat('b', 64), 'ready'
|
||||
),
|
||||
(
|
||||
'a0000000-0000-4000-8000-000000000011',
|
||||
'a0000000-0000-4000-8000-000000000002',
|
||||
'client', 'contract-smoke', 'deterministic',
|
||||
'measurement-smoke-client', '1.0.0', repeat('c', 64),
|
||||
'measurement-event.v1', repeat('d', 64), 'ready'
|
||||
);
|
||||
|
||||
INSERT INTO app.measurement_event (
|
||||
measurement_id, session_id, construct, dimension, perspective, source_kind,
|
||||
instrument_id, instrument_version, value, scale_min, scale_max,
|
||||
model_run_id, visible_to
|
||||
) VALUES
|
||||
(
|
||||
'a0000000-0000-4000-8000-000000000020',
|
||||
'a0000000-0000-4000-8000-000000000002',
|
||||
'working_alliance', 'learner_goal', 'learner_self_report', 'learner_reported',
|
||||
'phase3-prepost', 'design-1', 0.4, 0, 1,
|
||||
NULL, ARRAY['counselor','evaluator']::text[]
|
||||
),
|
||||
(
|
||||
'a0000000-0000-4000-8000-000000000021',
|
||||
'a0000000-0000-4000-8000-000000000002',
|
||||
'working_alliance', 'observer_goal', 'independent_observer', 'model_inferred',
|
||||
'vignette-fast-evaluator', 'legacy-1', 0.3, 0, 1,
|
||||
'a0000000-0000-4000-8000-000000000010', ARRAY['evaluator']::text[]
|
||||
),
|
||||
(
|
||||
'a0000000-0000-4000-8000-000000000022',
|
||||
'a0000000-0000-4000-8000-000000000002',
|
||||
'working_alliance', 'client_goal', 'client_agent_report', 'agent_reported',
|
||||
'vignette-fast-evaluator', 'legacy-1', 0.2, 0, 1,
|
||||
'a0000000-0000-4000-8000-000000000011', ARRAY['client']::text[]
|
||||
);
|
||||
|
||||
SET LOCAL ROLE :"app_role";
|
||||
|
||||
SELECT set_config('app.current_uid', 'a0000000-0000-4000-8000-000000000001', true);
|
||||
SELECT set_config('app.current_role', 'learner', true);
|
||||
SELECT set_config('app.ai_context', '0', true);
|
||||
SELECT set_config('app.current_ai_view', '', true);
|
||||
|
||||
DO $$
|
||||
DECLARE actual integer;
|
||||
BEGIN
|
||||
SELECT count(*) INTO actual
|
||||
FROM app.measurement_event
|
||||
WHERE session_id = 'a0000000-0000-4000-8000-000000000002';
|
||||
IF actual <> 1 THEN
|
||||
RAISE EXCEPTION 'learner RLS leak: expected 1 counselor-visible event, got %', actual;
|
||||
END IF;
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM app.measurement_event
|
||||
WHERE measurement_id IN (
|
||||
'a0000000-0000-4000-8000-000000000021',
|
||||
'a0000000-0000-4000-8000-000000000022'
|
||||
)
|
||||
) THEN
|
||||
RAISE EXCEPTION 'learner RLS exposed evaluator/client-agent measurement';
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
SELECT set_config('app.ai_context', '1', true);
|
||||
SELECT set_config('app.current_ai_view', 'client', true);
|
||||
|
||||
DO $$
|
||||
DECLARE actual integer;
|
||||
BEGIN
|
||||
SELECT count(*) INTO actual
|
||||
FROM app.measurement_event
|
||||
WHERE session_id = 'a0000000-0000-4000-8000-000000000002';
|
||||
IF actual <> 1 THEN
|
||||
RAISE EXCEPTION 'client AI view leak: expected 1 client event, got %', actual;
|
||||
END IF;
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM app.measurement_event
|
||||
WHERE measurement_id IN (
|
||||
'a0000000-0000-4000-8000-000000000020',
|
||||
'a0000000-0000-4000-8000-000000000021'
|
||||
)
|
||||
) THEN
|
||||
RAISE EXCEPTION 'client AI view exposed counselor/evaluator measurement';
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
SELECT set_config('app.current_ai_view', 'evaluator', true);
|
||||
|
||||
DO $$
|
||||
DECLARE actual integer;
|
||||
BEGIN
|
||||
SELECT count(*) INTO actual
|
||||
FROM app.measurement_event
|
||||
WHERE session_id = 'a0000000-0000-4000-8000-000000000002';
|
||||
IF actual <> 2 THEN
|
||||
RAISE EXCEPTION 'evaluator AI view mismatch: expected 2 events, got %', actual;
|
||||
END IF;
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM app.measurement_event
|
||||
WHERE measurement_id = 'a0000000-0000-4000-8000-000000000022'
|
||||
) THEN
|
||||
RAISE EXCEPTION 'evaluator AI view exposed client-agent-only measurement';
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
SELECT set_config('app.ai_context', '0', true);
|
||||
SELECT set_config('app.current_ai_view', '', true);
|
||||
|
||||
RESET ROLE;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
BEGIN
|
||||
UPDATE app.measurement_event
|
||||
SET value = 0.9
|
||||
WHERE measurement_id = 'a0000000-0000-4000-8000-000000000020';
|
||||
RAISE EXCEPTION 'measurement_event UPDATE unexpectedly succeeded';
|
||||
EXCEPTION WHEN SQLSTATE '55000' THEN
|
||||
NULL;
|
||||
END;
|
||||
|
||||
BEGIN
|
||||
DELETE FROM audit.model_run
|
||||
WHERE model_run_id = 'a0000000-0000-4000-8000-000000000010';
|
||||
RAISE EXCEPTION 'model_run DELETE unexpectedly succeeded';
|
||||
EXCEPTION WHEN SQLSTATE '55000' THEN
|
||||
NULL;
|
||||
END;
|
||||
END;
|
||||
$$;
|
||||
|
||||
SELECT json_build_object(
|
||||
'ok', true,
|
||||
'learner_visible', 1,
|
||||
'client_visible', 1,
|
||||
'evaluator_visible', 2,
|
||||
'cross_view_leaks', 0,
|
||||
'append_only_guards', 2
|
||||
) AS measurement_ledger_smoke;
|
||||
|
||||
ROLLBACK;
|
||||
Loading…
Add table
Add a link
Reference in a new issue