@team-semicolon/semicolony-cli 4.18.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +200 -0
- package/NOTICE +8 -0
- package/README.md +152 -0
- package/dist/bundle.js +2887 -0
- package/dist/templates/launchd/ai.semicolony.host-signals-sidecar.plist +40 -0
- package/migrations/001_initial.sql +280 -0
- package/migrations/002_add_indexes.sql +11 -0
- package/migrations/003_add_fk.sql +32 -0
- package/migrations/004_session_count_trigger.sql +35 -0
- package/migrations/005_bot_workspace_audits.sql +16 -0
- package/migrations/006_bot_kb_subscriptions.sql +24 -0
- package/migrations/007_flatten_skill_names.sql +16 -0
- package/migrations/008_bot_workspace_files.sql +14 -0
- package/migrations/009_enforce_flat_skill_names.sql +53 -0
- package/migrations/010_bot_delegation.sql +27 -0
- package/migrations/011_drop_legacy_tables.sql +35 -0
- package/migrations/012_drop_bot_knowledge.sql +16 -0
- package/migrations/013_kb_workspace_domains.sql +88 -0
- package/migrations/014_timestamp_to_timestamptz.sql +33 -0
- package/migrations/015_kb_domain_enforcement.sql +83 -0
- package/migrations/016_ontology_redesign.sql +108 -0
- package/migrations/017_ontology_instance_model.sql +151 -0
- package/migrations/018_type_schema.sql +11 -0
- package/migrations/019_test_management.sql +69 -0
- package/migrations/020_bot_workspace_standard.sql +174 -0
- package/migrations/021_drop_dead_tables.sql +8 -0
- package/migrations/021_test_declarative.sql +19 -0
- package/migrations/022_bot_ontology_type.sql +38 -0
- package/migrations/022_kb_schema_enforcement.sql +77 -0
- package/migrations/023_decision_key_cleanup.ts +154 -0
- package/migrations/024_embedding_backfill.ts +137 -0
- package/migrations/025_kb_flat_keys.sql +33 -0
- package/migrations/026_drop_session_log.sql +19 -0
- package/migrations/027_kb_manager_skill.sql +22 -0
- package/migrations/028_skill_definitions_to_semicolony.sql +19 -0
- package/migrations/029_agents_citation_max_lines.sql +6 -0
- package/migrations/030_team_ontology.sql +54 -0
- package/migrations/031_gfp_tables.sql +101 -0
- package/migrations/031_kb_manager_domain_register.sql +12 -0
- package/migrations/032_gfp_skill_and_callback.sql +40 -0
- package/migrations/032_kebab_case_keys.sql +33 -0
- package/migrations/033_skill_workspace_rules.sql +10 -0
- package/migrations/034_current_to_date_keys.sql +13 -0
- package/migrations/034_current_to_date_keys.ts +104 -0
- package/migrations/035_bot_budgets.sql +51 -0
- package/migrations/036_gfp_stitch_design.sql +35 -0
- package/migrations/037_gfp_qa_sections.sql +13 -0
- package/migrations/038_gfp_phase_split.sql +26 -0
- package/migrations/039_meeting_audio_data.sql +2 -0
- package/migrations/040_bot_commitments.sql +68 -0
- package/migrations/041_palette_previews.sql +13 -0
- package/migrations/042_gfp_parallel_tracks.sql +37 -0
- package/migrations/043_blocker_key.sql +13 -0
- package/migrations/044_gfp_stitch_screenshots.sql +9 -0
- package/migrations/045_service_table_rename_and_projection.sql +150 -0
- package/migrations/046_service_ops_tables.sql +75 -0
- package/migrations/047_update_gfp_manager_skill.sql +16 -0
- package/migrations/048_service_migration_skill.sql +23 -0
- package/migrations/049_service_features.sql +39 -0
- package/migrations/050_service_kpi_action_items.sql +87 -0
- package/migrations/051_update_service_migration_skill_prompt.sql +9 -0
- package/migrations/052_feature_iteration_link.sql +11 -0
- package/migrations/052_services_table_rename.sql +149 -0
- package/migrations/053_feature_discovery.sql +47 -0
- package/migrations/054_deploy_verification.sql +17 -0
- package/migrations/055_feature_lifecycle.sql +37 -0
- package/migrations/056_service_incident_schema.sql +16 -0
- package/migrations/057_decision_date_to_metadata.ts +173 -0
- package/migrations/058_incubator_kb_schema.sql +8 -0
- package/migrations/059_incubator_sessions.sql +29 -0
- package/migrations/060_skill_reference_files.sql +8 -0
- package/migrations/061_cron_trigger_bridge.sql +7 -0
- package/migrations/062_bot_slack_profiles.sql +21 -0
- package/migrations/063_rename_gfp_skills.sql +7 -0
- package/migrations/064_bot_cost_log.sql +11 -0
- package/migrations/065_hub_spoke_orchestration.sql +35 -0
- package/migrations/066_cost_log_commitment.sql +9 -0
- package/migrations/067_module_ontology_type.sql +44 -0
- package/migrations/068_migrate_incubator_data.sql +32 -0
- package/migrations/069_action_items_sot.sql +156 -0
- package/migrations/069_cost_log_tokens.sql +45 -0
- package/migrations/070_services_sot_columns.sql +78 -0
- package/migrations/071_cleanup_deprecated_service_kb.sql +38 -0
- package/migrations/072_incubator_heartbeat.sql +12 -0
- package/migrations/072_service_role_schema.sql +57 -0
- package/migrations/073_service_type_and_platform.sql +8 -0
- package/migrations/074_schema_ref_type.sql +16 -0
- package/migrations/075_routing_delegation.sql +34 -0
- package/migrations/076_meeting_service_link.sql +5 -0
- package/migrations/077_agents_ontology_type.sql +93 -0
- package/migrations/078_incubator_agent.sql +45 -0
- package/migrations/079_drop_audio_blob_url.sql +4 -0
- package/migrations/080_kb_metadata_indexing.sql +9 -0
- package/migrations/081_person_unification.sql +41 -0
- package/migrations/082_discord_channel.sql +3 -0
- package/migrations/084_deprecate_kpi_metrics_table.sql +5 -0
- package/migrations/085_meeting_target_domain.sql +37 -0
- package/migrations/086_skill_routing_new_skills.sql +23 -0
- package/migrations/087_skill_routing_second_opinion.sql +8 -0
- package/migrations/088_meeting_notion_sync.sql +10 -0
- package/migrations/089_bot_commitments_dedup.sql +17 -0
- package/migrations/090_incubator_discord_guild.sql +8 -0
- package/migrations/091_drop_deprecated_gfp_kpi_views.sql +65 -0
- package/migrations/092_ontology_channel_mapping.sql +28 -0
- package/migrations/093_update_bot_workspace_paths.sql +15 -0
- package/migrations/094_cron_run_tracking.sql +28 -0
- package/migrations/095_drop_bot_cron_runs.sql +7 -0
- package/migrations/096_kb_pipeline_keys.sql +66 -0
- package/migrations/097_drop_empty_service_tables.sql +83 -0
- package/migrations/098_migrate_features_materials_drop.sql +119 -0
- package/migrations/099_migrate_sections_drop.sql +52 -0
- package/migrations/099_seed_cron_poller_tick.sql +14 -0
- package/migrations/100_migrate_services_drop.sql +57 -0
- package/migrations/101_drop_services.sql +5 -0
- package/migrations/102_cost_log_session_dedup.sql +13 -0
- package/migrations/103_board.sql +57 -0
- package/migrations/104_agent_factory.sql +284 -0
- package/migrations/105_kb_notify.sql +44 -0
- package/migrations/106_office_id_agents_commands.sql +73 -0
- package/migrations/107_agent_service_credentials.sql +79 -0
- package/migrations/108_drop_l2_ontology_seeds.sql +16 -0
- package/migrations/109_generic_ontology_descriptions.sql +21 -0
- package/migrations/110_kb_manager_skill_l2_cleanup.sql +34 -0
- package/migrations/111_drop_l2_team_ontology_seeds.sql +20 -0
- package/migrations/112_fix_pipeline_schema_and_role_trigger.sql +83 -0
- package/migrations/113_kb_history.sql +53 -0
- package/migrations/114_runtime_target_columns.sql +26 -0
- package/migrations/115_runtime_source_columns.sql +52 -0
- package/migrations/116_commitment_pattern_health.sql +81 -0
- package/migrations/117_commitment_pattern_alert_claims.sql +33 -0
- package/migrations/118_retire_semiclaw_semicolonybot_alias.sql +30 -0
- package/migrations/119_commitment_events.sql +51 -0
- package/migrations/120_host_signals.sql +51 -0
- package/migrations/121_agent_spec_derived_runtime_metadata.sql +68 -0
- package/migrations/122_agent_spec_derived_fk_policy.sql +18 -0
- package/migrations/123_agent_spec_projection_skip_targets.sql +24 -0
- package/migrations/124_bot_commitments_notify.sql +26 -0
- package/migrations/125_agent_personas.sql +36 -0
- package/migrations/128_entity_relations.sql +125 -0
- package/migrations/129_kb_multitenant_gateway.sql +86 -0
- package/migrations/130_jewelry_relation_types.sql +36 -0
- package/migrations/131_concierge_requests.sql +38 -0
- package/migrations/132_kb_supersession.sql +27 -0
- package/migrations/133_kb_claims.sql +52 -0
- package/migrations/134_migration_registry.sql +18 -0
- package/migrations/135_sc_roles.sql +102 -0
- package/migrations/136_runtime_tenant_columns.sql +71 -0
- package/migrations/137_runtime_backfill_team_semicolon.sql +131 -0
- package/migrations/138_runtime_constraints_not_valid.sql +56 -0
- package/migrations/139_tenant_vms.sql +31 -0
- package/migrations/140_fleet_slots.sql +23 -0
- package/migrations/141_provisioning_jobs.sql +29 -0
- package/migrations/142_rls_enable_semicolony.sql +129 -0
- package/migrations/143_rls_enable_public.sql +54 -0
- package/migrations/144_worker_device_registry.sql +211 -0
- package/migrations/145_workspace_profile_workstation_policy.sql +39 -0
- package/migrations/146_worker_profile_repo_scope.sql +24 -0
- package/migrations/147_worker_profile_semo_ops_repo_rename.sql +18 -0
- package/migrations/148_momo_runtime_convergence.sql +92 -0
- package/migrations/README.md +88 -0
- package/migrations-sqlite/kb/001_initial.sql +56 -0
- package/migrations-sqlite/ops/001_initial.sql +53 -0
- package/migrations-sqlite/ops/002_action_items.sql +48 -0
- package/package.json +78 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
-- 076_person_unification.sql
|
|
2
|
+
-- team 타입과 person 타입을 person으로 통합
|
|
3
|
+
|
|
4
|
+
BEGIN;
|
|
5
|
+
|
|
6
|
+
-- 1. person 스키마에 team 전용 키 추가
|
|
7
|
+
INSERT INTO semicolony.kb_type_schema (type_key, scheme_key, key_type, required, scheme_description, value_hint)
|
|
8
|
+
VALUES
|
|
9
|
+
('person', 'nickname', 'singleton', false, '닉네임', '팀 내 닉네임'),
|
|
10
|
+
('person', 'slack-id', 'singleton', false, 'Slack ID', 'Slack User ID (e.g. URSQYUNQJ)'),
|
|
11
|
+
('person', 'discord-id', 'singleton', false, 'Discord ID', 'Discord User ID (snowflake)'),
|
|
12
|
+
('person', 'tech-stack', 'singleton', false, '기술스택', '주요 기술/언어/프레임워크'),
|
|
13
|
+
('person', 'career', 'singleton', false, '경력', '이전 회사, 경력 요약'),
|
|
14
|
+
('person', 'compensation', 'singleton', false, 'compensation', '보상 구조'),
|
|
15
|
+
('person', 'dm-channel', 'singleton', false, 'dm-channel', 'Slack DM channel ID'),
|
|
16
|
+
('person', 'communication-profile', 'singleton', false,
|
|
17
|
+
'봇 커뮤니케이션 프로필 — 기술수준, 접근권한, 톤 지시',
|
|
18
|
+
'YAML: tech_level, access_level, dri_scope, comm_style, language')
|
|
19
|
+
ON CONFLICT (type_key, scheme_key) DO NOTHING;
|
|
20
|
+
|
|
21
|
+
-- 2. person의 role을 collection으로 변경
|
|
22
|
+
UPDATE semicolony.kb_type_schema SET key_type = 'collection',
|
|
23
|
+
value_hint = 'role/overall, role/{project-domain} 등 프로젝트별 역할'
|
|
24
|
+
WHERE type_key = 'person' AND scheme_key = 'role';
|
|
25
|
+
|
|
26
|
+
-- 3. ontology: team → person 타입 변경
|
|
27
|
+
UPDATE semicolony.ontology SET entity_type = 'person' WHERE entity_type = 'team';
|
|
28
|
+
|
|
29
|
+
-- 4. 기존 person 도메인에 organization 키 placeholder 삽입 (인스턴스별 수동 채움)
|
|
30
|
+
-- 세미콜론 내부 backfill 은 이 migration 이 처음 적용된 시점에 한해 효력 발휘.
|
|
31
|
+
-- OSS fresh install: 이 시점에 person 도메인 자체가 0건이므로 no-op.
|
|
32
|
+
-- (이전 버전은 세미콜론 팀원 13명 닉네임을 IN 절에 포함했으나 누출 방지를 위해 제거됨.)
|
|
33
|
+
-- organization 키 값은 인스턴스가 직접 채워야 한다 — 자동 시드하지 않음.
|
|
34
|
+
|
|
35
|
+
-- 5. team 타입 스키마 제거
|
|
36
|
+
DELETE FROM semicolony.kb_type_schema WHERE type_key = 'team';
|
|
37
|
+
|
|
38
|
+
-- 6. ontology_types에서 team 제거
|
|
39
|
+
DELETE FROM semicolony.ontology_types WHERE type_key = 'team';
|
|
40
|
+
|
|
41
|
+
COMMIT;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
-- Phase 3: service_kpi_metrics 테이블 deprecated 마킹
|
|
2
|
+
-- KPI 데이터는 KB metadata가 SoT. 이 테이블은 historical fallback 전용.
|
|
3
|
+
-- 전환 완료 후 (1개월 검증) 별도 마이그레이션으로 DROP 예정.
|
|
4
|
+
|
|
5
|
+
COMMENT ON TABLE semicolony.service_kpi_metrics IS 'DEPRECATED: KPI data now lives in KB metadata (key=kpi, sub_key=YYYY-MM-DD). This table is retained for historical fallback reads only. Do not insert new records.';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
-- Phase 6: meetings.service_id → target_domain 전환
|
|
2
|
+
-- service_id FK를 ontology domain 기반 target_domain으로 통일 (action_items 패턴과 동일)
|
|
3
|
+
|
|
4
|
+
-- Step 1: target_domain 컬럼 추가
|
|
5
|
+
ALTER TABLE semicolony.meetings
|
|
6
|
+
ADD COLUMN IF NOT EXISTS target_domain VARCHAR(100)
|
|
7
|
+
REFERENCES semicolony.ontology(domain);
|
|
8
|
+
|
|
9
|
+
-- Step 2: 기존 service_id → target_domain 데이터 마이그레이션
|
|
10
|
+
-- ontology에 등록된 도메인만 FK 위반 없이 안전하게 마이그레이션
|
|
11
|
+
UPDATE semicolony.meetings m
|
|
12
|
+
SET target_domain = s.service_domain
|
|
13
|
+
FROM semicolony.services s
|
|
14
|
+
JOIN semicolony.ontology o ON o.domain = s.service_domain
|
|
15
|
+
WHERE m.service_id = s.service_id
|
|
16
|
+
AND m.service_id IS NOT NULL
|
|
17
|
+
AND s.service_domain IS NOT NULL
|
|
18
|
+
AND m.target_domain IS NULL;
|
|
19
|
+
|
|
20
|
+
-- Step 2.5: 마이그레이션 후 누락 행 검증
|
|
21
|
+
DO $$
|
|
22
|
+
DECLARE unmigrated INT;
|
|
23
|
+
BEGIN
|
|
24
|
+
SELECT COUNT(*) INTO unmigrated
|
|
25
|
+
FROM semicolony.meetings
|
|
26
|
+
WHERE service_id IS NOT NULL AND target_domain IS NULL;
|
|
27
|
+
IF unmigrated > 0 THEN
|
|
28
|
+
RAISE WARNING '% meetings have service_id but no target_domain (service_domain missing from ontology)', unmigrated;
|
|
29
|
+
END IF;
|
|
30
|
+
END $$;
|
|
31
|
+
|
|
32
|
+
-- Step 3: service_id는 당분간 유지 (하위호환)
|
|
33
|
+
COMMENT ON COLUMN semicolony.meetings.service_id IS 'DEPRECATED: Use target_domain instead. Will be removed after migration period.';
|
|
34
|
+
|
|
35
|
+
-- Step 4: 인덱스
|
|
36
|
+
CREATE INDEX IF NOT EXISTS idx_meetings_target_domain ON semicolony.meetings(target_domain)
|
|
37
|
+
WHERE target_domain IS NOT NULL;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
-- 086: 신규 스킬 6종 라우팅 등록
|
|
2
|
+
|
|
3
|
+
INSERT INTO semicolony.bot_delegation (from_bot_id, to_bot_id, delegation_type, domains, method, metadata)
|
|
4
|
+
VALUES
|
|
5
|
+
('orchestrator', 'reviewclaw', 'skill-routing',
|
|
6
|
+
ARRAY['/security-scan','보안 스캔','security scan','취약점 점검','OWASP','시크릿 스캔','secret scan','npm audit'],
|
|
7
|
+
'keyword', '{"skill":"security-scan","label":"security-scan"}'),
|
|
8
|
+
('orchestrator', 'reviewclaw', 'skill-routing',
|
|
9
|
+
ARRAY['테스트 생성','test generate','테스트 만들어','add tests','missing tests','테스트 커버리지'],
|
|
10
|
+
'keyword', '{"skill":"test-generator","label":"test-generator"}'),
|
|
11
|
+
('orchestrator', 'designclaw', 'skill-routing',
|
|
12
|
+
ARRAY['visual qa','visual-qa','/visual-qa','시각 QA','레이아웃 점검','UI 검증','스크린샷 비교','visual regression'],
|
|
13
|
+
'keyword', '{"skill":"visual-qa","label":"visual-qa"}'),
|
|
14
|
+
('orchestrator', 'growthclaw', 'skill-routing',
|
|
15
|
+
ARRAY['/seo-check','seo crawl','seo 크롤링','메타태그 점검','on-page seo','heading 점검','sitemap 확인'],
|
|
16
|
+
'keyword', '{"skill":"seo-crawl","label":"seo-crawl"}'),
|
|
17
|
+
('orchestrator', 'infraclaw', 'skill-routing',
|
|
18
|
+
ARRAY['/canary-check','canary check','배포 후 점검','post-deploy check','카나리 체크','서비스 헬스체크','deploy health'],
|
|
19
|
+
'keyword', '{"skill":"canary-monitor","label":"canary-monitor"}'),
|
|
20
|
+
('orchestrator', 'workclaw', 'skill-routing',
|
|
21
|
+
ARRAY['migration verify','마이그레이션 검증','migration 검증','migration check','마이그레이션 점검','db migration'],
|
|
22
|
+
'keyword', '{"skill":"migration-verify","label":"migration-verify"}')
|
|
23
|
+
ON CONFLICT DO NOTHING;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-- 087: second-opinion 스킬 라우팅 등록
|
|
2
|
+
|
|
3
|
+
INSERT INTO semicolony.bot_delegation (from_bot_id, to_bot_id, delegation_type, domains, method, metadata)
|
|
4
|
+
VALUES
|
|
5
|
+
('orchestrator', 'reviewclaw', 'skill-routing',
|
|
6
|
+
ARRAY['second-opinion','세컨드 오피니언','cross-model','교차 검증','/second-opinion'],
|
|
7
|
+
'keyword', '{"skill":"second-opinion","label":"second-opinion"}')
|
|
8
|
+
ON CONFLICT DO NOTHING;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
ALTER TABLE semicolony.meetings
|
|
2
|
+
ADD COLUMN IF NOT EXISTS notion_page_id VARCHAR(100),
|
|
3
|
+
ADD COLUMN IF NOT EXISTS notion_url TEXT,
|
|
4
|
+
ADD COLUMN IF NOT EXISTS notion_sync_status VARCHAR(20) DEFAULT 'pending'
|
|
5
|
+
CHECK (notion_sync_status IN ('pending', 'synced', 'failed', 'skipped')),
|
|
6
|
+
ADD COLUMN IF NOT EXISTS notion_sync_error TEXT;
|
|
7
|
+
|
|
8
|
+
CREATE INDEX IF NOT EXISTS idx_meetings_notion_sync
|
|
9
|
+
ON semicolony.meetings(notion_sync_status)
|
|
10
|
+
WHERE notion_sync_status = 'failed';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
-- 089: bot_commitments dedup guard
|
|
2
|
+
-- 동일한 Slack 이벤트(msg.ts)가 여러 slack-router 인스턴스에 의해 중복 dispatch되는
|
|
3
|
+
-- 경우 commitment이 중복 생성되는 것을 DB 레벨에서 차단한다.
|
|
4
|
+
--
|
|
5
|
+
-- 배경: 4/12-13 period에 slack-router가 2개 동시 실행되어 거의 모든 commitment이
|
|
6
|
+
-- 15~20초 간격으로 짝을 이뤄 중복 생성됨. 루터 정리로 즉발은 해결됐으나 재발 방지를
|
|
7
|
+
-- 위해 DB 유니크 제약을 추가한다.
|
|
8
|
+
--
|
|
9
|
+
-- 키: (bot_id, pipeline_context->>'slack_event_id')
|
|
10
|
+
-- 조건: status IN ('pending','active') AND pipeline_context ? 'slack_event_id'
|
|
11
|
+
-- - done/failed 행은 포함하지 않아 재처리(재시도)는 허용
|
|
12
|
+
-- - slack_event_id가 없는 로컬/크론/github 경로는 영향 없음
|
|
13
|
+
|
|
14
|
+
CREATE UNIQUE INDEX IF NOT EXISTS bot_commitments_slack_event_uniq
|
|
15
|
+
ON semicolony.bot_commitments (bot_id, (pipeline_context->>'slack_event_id'))
|
|
16
|
+
WHERE status IN ('pending', 'active')
|
|
17
|
+
AND pipeline_context ? 'slack_event_id';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-- 090_incubator_discord_guild.sql
|
|
2
|
+
-- incubator_sessions에 discord_guild 컬럼 추가 (Discord guild 단위 incubator 라우팅)
|
|
3
|
+
ALTER TABLE semicolony.incubator_sessions ADD COLUMN IF NOT EXISTS discord_guild TEXT;
|
|
4
|
+
|
|
5
|
+
-- SEMICOLONY Incubator 1기 서버 매핑
|
|
6
|
+
UPDATE semicolony.incubator_sessions
|
|
7
|
+
SET discord_guild = '1493481703002476658'
|
|
8
|
+
WHERE status = 'active' AND discord_guild IS NULL;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
-- 091: 레거시 호환 VIEW + deprecated 테이블/컬럼 최종 제거
|
|
2
|
+
--
|
|
3
|
+
-- 선행 조건:
|
|
4
|
+
-- 045/052: gfp_* → service_* 테이블 리네임 + 호환 VIEW 생성
|
|
5
|
+
-- 069: action_items 리네임 + service_action_items VIEW 생성
|
|
6
|
+
-- 084: service_kpi_metrics deprecated (KB metadata가 SoT)
|
|
7
|
+
-- 085: meetings.service_id deprecated (target_domain 대체)
|
|
8
|
+
--
|
|
9
|
+
-- 코드 참조 제거 확인:
|
|
10
|
+
-- - gfp_* VIEW: 코드 참조 0건 (service_* 직접 참조로 전환)
|
|
11
|
+
-- - service_kpi_metrics: DB fallback 코드 제거됨 (KB-only)
|
|
12
|
+
-- - meetings.service_id: 코드에서 완전 제거됨
|
|
13
|
+
--
|
|
14
|
+
-- 사전 백업 권장:
|
|
15
|
+
-- pg_dump --table=semicolony.service_kpi_metrics -f backup_kpi_metrics.sql
|
|
16
|
+
|
|
17
|
+
BEGIN;
|
|
18
|
+
|
|
19
|
+
-- ── Guard: meetings.service_id 마이그레이션 완료 확인 (멱등) ──
|
|
20
|
+
DO $$
|
|
21
|
+
DECLARE
|
|
22
|
+
col_exists BOOLEAN;
|
|
23
|
+
unmigrated INT;
|
|
24
|
+
BEGIN
|
|
25
|
+
SELECT EXISTS (
|
|
26
|
+
SELECT 1 FROM information_schema.columns
|
|
27
|
+
WHERE table_schema = 'semicolony' AND table_name = 'meetings' AND column_name = 'service_id'
|
|
28
|
+
) INTO col_exists;
|
|
29
|
+
|
|
30
|
+
IF NOT col_exists THEN
|
|
31
|
+
RAISE NOTICE 'service_id column already dropped — skipping guard';
|
|
32
|
+
RETURN;
|
|
33
|
+
END IF;
|
|
34
|
+
|
|
35
|
+
SELECT COUNT(*) INTO unmigrated
|
|
36
|
+
FROM semicolony.meetings
|
|
37
|
+
WHERE service_id IS NOT NULL AND target_domain IS NULL;
|
|
38
|
+
IF unmigrated > 0 THEN
|
|
39
|
+
RAISE EXCEPTION '% meetings still have service_id without target_domain — run 085 data migration first', unmigrated;
|
|
40
|
+
END IF;
|
|
41
|
+
END $$;
|
|
42
|
+
|
|
43
|
+
-- ── 1. 레거시 호환 VIEW 제거 (의존 순서 준수) ──
|
|
44
|
+
|
|
45
|
+
-- gfp_projects가 service_projects를 참조하므로 먼저 제거
|
|
46
|
+
DROP VIEW IF EXISTS semicolony.gfp_projects CASCADE;
|
|
47
|
+
DROP VIEW IF EXISTS semicolony.gfp_phase_sections CASCADE;
|
|
48
|
+
DROP VIEW IF EXISTS semicolony.gfp_materials CASCADE;
|
|
49
|
+
DROP VIEW IF EXISTS semicolony.gfp_research_tasks CASCADE;
|
|
50
|
+
DROP VIEW IF EXISTS semicolony.gfp_infra_requests CASCADE;
|
|
51
|
+
|
|
52
|
+
-- gfp_projects 제거 후 안전하게 제거 가능
|
|
53
|
+
DROP VIEW IF EXISTS semicolony.service_projects CASCADE;
|
|
54
|
+
DROP VIEW IF EXISTS semicolony.service_action_items CASCADE;
|
|
55
|
+
|
|
56
|
+
-- ── 2. service_kpi_metrics 테이블 제거 ──
|
|
57
|
+
-- leaf 테이블 (incoming FK 없음). 인덱스 2개 + 트리거 자동 제거.
|
|
58
|
+
DROP TABLE IF EXISTS semicolony.service_kpi_metrics;
|
|
59
|
+
|
|
60
|
+
-- ── 3. meetings.service_id 컬럼 제거 ──
|
|
61
|
+
DROP INDEX IF EXISTS semicolony.idx_meetings_service;
|
|
62
|
+
ALTER TABLE semicolony.meetings DROP CONSTRAINT IF EXISTS meetings_service_id_fkey;
|
|
63
|
+
ALTER TABLE semicolony.meetings DROP COLUMN IF EXISTS service_id;
|
|
64
|
+
|
|
65
|
+
COMMIT;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-- 092: ontology 채널 매핑 컬럼 추가
|
|
2
|
+
--
|
|
3
|
+
-- Orchestrator 라우터가 services 테이블 대신 ontology에서 직접 채널→도메인 매핑을 조회.
|
|
4
|
+
-- 비-서비스 도메인(organization, team, module 등)도 채널 라우팅 가능.
|
|
5
|
+
--
|
|
6
|
+
-- 선행 조건:
|
|
7
|
+
-- 070: services.slack_channel 컬럼 존재
|
|
8
|
+
-- 082: services.discord_channel 컬럼 존재
|
|
9
|
+
|
|
10
|
+
-- Step 1: ontology에 채널 컬럼 추가
|
|
11
|
+
ALTER TABLE semicolony.ontology
|
|
12
|
+
ADD COLUMN IF NOT EXISTS slack_channel TEXT,
|
|
13
|
+
ADD COLUMN IF NOT EXISTS discord_channel TEXT;
|
|
14
|
+
|
|
15
|
+
-- Step 2: 라우터 성능용 부분 인덱스
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_ontology_slack_channel
|
|
17
|
+
ON semicolony.ontology (slack_channel) WHERE slack_channel IS NOT NULL;
|
|
18
|
+
CREATE INDEX IF NOT EXISTS idx_ontology_discord_channel
|
|
19
|
+
ON semicolony.ontology (discord_channel) WHERE discord_channel IS NOT NULL;
|
|
20
|
+
|
|
21
|
+
-- Step 3: services → ontology 기존 매핑 역동기화
|
|
22
|
+
UPDATE semicolony.ontology o
|
|
23
|
+
SET slack_channel = s.slack_channel,
|
|
24
|
+
discord_channel = s.discord_channel
|
|
25
|
+
FROM semicolony.services s
|
|
26
|
+
WHERE o.domain = s.service_domain
|
|
27
|
+
AND o.entity_type IN ('service', 'platform', 'module')
|
|
28
|
+
AND (s.slack_channel IS NOT NULL OR s.discord_channel IS NOT NULL);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- 093: bot_status.workspace_path 레거시 경로 정리
|
|
2
|
+
--
|
|
3
|
+
-- Migration 078 (incubator_agent) 및 초기 시드가 workspace_path를
|
|
4
|
+
-- '~/.semicolony-bot-sessions/{bot}' 또는 '~/.openclaw-{bot}/workspace'로 기록.
|
|
5
|
+
-- 2026-04-15 봇 워크스페이스 통합 이후 SoT는 '~/.semicolony/workspaces/{bot}'.
|
|
6
|
+
-- `semicolony bots sync`로 자동 반영되는 봇은 이미 갱신됐으나, sync 경로를 타지 않는
|
|
7
|
+
-- 봇(incubator 등)은 수동 정리가 필요하다.
|
|
8
|
+
|
|
9
|
+
UPDATE semicolony.bot_status
|
|
10
|
+
SET workspace_path = '~/.semicolony/workspaces/' || bot_id
|
|
11
|
+
WHERE workspace_path LIKE '~/.semicolony-bot-sessions/%'
|
|
12
|
+
OR workspace_path LIKE '~/.openclaw-%'
|
|
13
|
+
OR workspace_path LIKE '/Users/%/.openclaw-%'
|
|
14
|
+
OR workspace_path LIKE '/Users/%/.semicolony-bot-sessions/%'
|
|
15
|
+
OR workspace_path LIKE '/Users/%/.semicolony/workspaces/%';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-- 062: Cron Run Tracking
|
|
2
|
+
-- bot_cron_jobs에 실행 결과 rollup 3컬럼 추가 + 신규 append-only bot_cron_runs 이력 테이블
|
|
3
|
+
|
|
4
|
+
ALTER TABLE semicolony.bot_cron_jobs
|
|
5
|
+
ADD COLUMN IF NOT EXISTS last_status TEXT,
|
|
6
|
+
ADD COLUMN IF NOT EXISTS last_error TEXT,
|
|
7
|
+
ADD COLUMN IF NOT EXISTS consecutive_failures INTEGER NOT NULL DEFAULT 0;
|
|
8
|
+
|
|
9
|
+
CREATE TABLE IF NOT EXISTS semicolony.bot_cron_runs (
|
|
10
|
+
id BIGSERIAL PRIMARY KEY,
|
|
11
|
+
bot_id TEXT NOT NULL,
|
|
12
|
+
job_id TEXT NOT NULL,
|
|
13
|
+
started_at TIMESTAMPTZ NOT NULL,
|
|
14
|
+
finished_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
15
|
+
duration_ms INTEGER,
|
|
16
|
+
status TEXT NOT NULL CHECK (status IN ('success','failure','timeout','skipped')),
|
|
17
|
+
error TEXT,
|
|
18
|
+
output_digest TEXT,
|
|
19
|
+
session_owner TEXT,
|
|
20
|
+
metadata JSONB NOT NULL DEFAULT '{}'::jsonb
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
CREATE INDEX IF NOT EXISTS idx_bot_cron_runs_job
|
|
24
|
+
ON semicolony.bot_cron_runs(bot_id, job_id, started_at DESC);
|
|
25
|
+
|
|
26
|
+
CREATE INDEX IF NOT EXISTS idx_bot_cron_runs_failure
|
|
27
|
+
ON semicolony.bot_cron_runs(status, started_at DESC)
|
|
28
|
+
WHERE status IN ('failure','timeout');
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- 095: bot_cron_runs 폐기 (commitment 통합)
|
|
2
|
+
-- cron 실행은 bot_commitments(source_type='cron')으로 기록한다.
|
|
3
|
+
-- bot_cron_jobs.last_status / last_error / consecutive_failures rollup 컬럼은 유지.
|
|
4
|
+
|
|
5
|
+
DROP INDEX IF EXISTS semicolony.idx_bot_cron_runs_failure;
|
|
6
|
+
DROP INDEX IF EXISTS semicolony.idx_bot_cron_runs_job;
|
|
7
|
+
DROP TABLE IF EXISTS semicolony.bot_cron_runs;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
-- 096: KB pipeline keys 등록
|
|
2
|
+
-- service_* 테이블 → KB 이식을 위한 type schema 키 등록
|
|
3
|
+
-- Phase 0: 선행 조건 — 새 KB 키들을 service 타입에 등록
|
|
4
|
+
|
|
5
|
+
-- 파이프라인 워크플로우 키 (PM 파이프라인이 관리)
|
|
6
|
+
INSERT INTO semicolony.kb_type_schema (type_key, scheme_key, scheme_description, required, value_hint, sort_order, key_type, source)
|
|
7
|
+
VALUES
|
|
8
|
+
('service', 'pipeline', '프로젝트 파이프라인 워크플로우 상태 (phase, lifecycle, preset 등)', false,
|
|
9
|
+
'metadata: {current_phase, infra_phase, lifecycle, service_type, parent_domain, preset, design_step}',
|
|
10
|
+
30, 'singleton', 'pipeline'),
|
|
11
|
+
('service', 'section', '파이프라인 섹션 (phase별 콘텐츠 블록)', false,
|
|
12
|
+
'sub_key: {track}/{phase}/{section_key}. metadata: {title, ordinal, status, source, qa_items}',
|
|
13
|
+
31, 'collection', 'pipeline'),
|
|
14
|
+
('service', 'material', '프로젝트 산출물 (기획서, 디자인 export 등)', false,
|
|
15
|
+
'sub_key: {material_id}. metadata: {material_type, phase_mapping}',
|
|
16
|
+
32, 'collection', 'manual'),
|
|
17
|
+
('service', 'feature', '서비스 기능 카탈로그', false,
|
|
18
|
+
'sub_key: {feature_slug}. metadata: {name, category, status, spec}',
|
|
19
|
+
33, 'collection', 'pipeline'),
|
|
20
|
+
('service', 'iteration', '운영 이터레이션 (스프린트)', false,
|
|
21
|
+
'sub_key: {title_slug}. metadata: {status, goal, started_at, completed_at}',
|
|
22
|
+
34, 'collection', 'manual'),
|
|
23
|
+
('service', 'incident', '운영 인시던트', false,
|
|
24
|
+
'sub_key: {YYYY-MM-DD}/{title_slug}. metadata: {severity, status, root_cause, resolution}',
|
|
25
|
+
35, 'collection', 'manual'),
|
|
26
|
+
('service', 'infra-request', '인프라 요청', false,
|
|
27
|
+
'sub_key: {request_id}. metadata: {category, priority, status}',
|
|
28
|
+
36, 'collection', 'pipeline'),
|
|
29
|
+
('service', 'research', '리서치 태스크', false,
|
|
30
|
+
'sub_key: {task_id}. metadata: {task_type, status, reference_urls}',
|
|
31
|
+
37, 'collection', 'pipeline'),
|
|
32
|
+
('service', 'session', '파이프라인 대화 세션 (discovery, conversation)', false,
|
|
33
|
+
'sub_key: {type}/{session_id}. metadata: 세션 상태',
|
|
34
|
+
38, 'collection', 'pipeline'),
|
|
35
|
+
('service', 'deploy-verify', '배포 검증 결과', false,
|
|
36
|
+
'sub_key: {infra_phase}/{YYYY-MM-DD}. metadata: {checks, overall_status, verified_by}',
|
|
37
|
+
39, 'collection', 'pipeline')
|
|
38
|
+
ON CONFLICT (type_key, scheme_key) DO UPDATE SET
|
|
39
|
+
scheme_description = EXCLUDED.scheme_description,
|
|
40
|
+
value_hint = EXCLUDED.value_hint,
|
|
41
|
+
sort_order = EXCLUDED.sort_order,
|
|
42
|
+
key_type = EXCLUDED.key_type,
|
|
43
|
+
source = EXCLUDED.source;
|
|
44
|
+
|
|
45
|
+
-- source 컬럼에 'pipeline' 값 허용 (기존: 'manual', 'projection')
|
|
46
|
+
-- CHECK 제약이 있을 경우 대비 — 없으면 무시됨
|
|
47
|
+
DO $$
|
|
48
|
+
DECLARE
|
|
49
|
+
_conname text;
|
|
50
|
+
BEGIN
|
|
51
|
+
-- kb_type_schema.source 컬럼에 CHECK 제약이 있는지 확인 후 'pipeline' 허용으로 확장
|
|
52
|
+
SELECT c.conname INTO _conname
|
|
53
|
+
FROM pg_constraint c
|
|
54
|
+
JOIN pg_class t ON c.conrelid = t.oid
|
|
55
|
+
JOIN pg_namespace n ON t.relnamespace = n.oid
|
|
56
|
+
WHERE n.nspname = 'semicolony' AND t.relname = 'kb_type_schema'
|
|
57
|
+
AND c.contype = 'c' AND c.conname LIKE '%source%'
|
|
58
|
+
LIMIT 1;
|
|
59
|
+
|
|
60
|
+
IF _conname IS NOT NULL THEN
|
|
61
|
+
EXECUTE format('ALTER TABLE semicolony.kb_type_schema DROP CONSTRAINT %I', _conname);
|
|
62
|
+
ALTER TABLE semicolony.kb_type_schema
|
|
63
|
+
ADD CONSTRAINT kb_type_schema_source_check
|
|
64
|
+
CHECK (source IN ('manual', 'projection', 'pipeline'));
|
|
65
|
+
END IF;
|
|
66
|
+
END $$;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
-- 097: Phase 1 — 빈/최소 데이터 service 테이블 6개 DROP
|
|
2
|
+
-- service_iterations (0건), service_incidents (0건), service_infra_requests (0건),
|
|
3
|
+
-- service_research_tasks (0건), feature_discovery_sessions (1건), feature_conversation_sessions (1건)
|
|
4
|
+
-- 코드는 이미 KB 기반으로 전환됨
|
|
5
|
+
|
|
6
|
+
-- 1. FK 제약 제거: action_items.iteration_id → service_iterations
|
|
7
|
+
ALTER TABLE semicolony.action_items DROP COLUMN IF EXISTS iteration_id;
|
|
8
|
+
|
|
9
|
+
-- 2. FK 제약 제거: service_features.iteration_id → service_iterations
|
|
10
|
+
ALTER TABLE semicolony.service_features DROP COLUMN IF EXISTS iteration_id;
|
|
11
|
+
|
|
12
|
+
-- 3. FK 제약 제거: service_sections.iteration_id (있을 경우)
|
|
13
|
+
ALTER TABLE semicolony.service_sections DROP COLUMN IF EXISTS iteration_id;
|
|
14
|
+
|
|
15
|
+
-- 4. 기존 세션 데이터 KB로 이식 (1건씩)
|
|
16
|
+
-- feature_discovery_sessions → KB session/discovery/{session_id}
|
|
17
|
+
DO $$
|
|
18
|
+
DECLARE
|
|
19
|
+
rec RECORD;
|
|
20
|
+
_domain TEXT;
|
|
21
|
+
BEGIN
|
|
22
|
+
FOR rec IN SELECT * FROM semicolony.feature_discovery_sessions LOOP
|
|
23
|
+
SELECT service_domain INTO _domain FROM semicolony.services WHERE service_id = rec.service_id;
|
|
24
|
+
IF _domain IS NOT NULL THEN
|
|
25
|
+
INSERT INTO semicolony.knowledge_base (domain, key, sub_key, content, created_by, metadata)
|
|
26
|
+
VALUES (
|
|
27
|
+
_domain, 'session', 'discovery/' || rec.session_id,
|
|
28
|
+
COALESCE(rec.source_url, ''),
|
|
29
|
+
'migration-097',
|
|
30
|
+
jsonb_build_object(
|
|
31
|
+
'session_id', rec.session_id,
|
|
32
|
+
'service_id', rec.service_id,
|
|
33
|
+
'source_url', rec.source_url,
|
|
34
|
+
'status', rec.status,
|
|
35
|
+
'candidates', rec.candidates,
|
|
36
|
+
'confirmed', rec.confirmed,
|
|
37
|
+
'screenshots', rec.screenshots,
|
|
38
|
+
'error', rec.error,
|
|
39
|
+
'created_at', rec.created_at::text
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
ON CONFLICT (domain, key, sub_key) DO NOTHING;
|
|
43
|
+
END IF;
|
|
44
|
+
END LOOP;
|
|
45
|
+
END $$;
|
|
46
|
+
|
|
47
|
+
-- feature_conversation_sessions → KB session/conversation/{session_id}
|
|
48
|
+
DO $$
|
|
49
|
+
DECLARE
|
|
50
|
+
rec RECORD;
|
|
51
|
+
_domain TEXT;
|
|
52
|
+
BEGIN
|
|
53
|
+
FOR rec IN SELECT * FROM semicolony.feature_conversation_sessions LOOP
|
|
54
|
+
SELECT service_domain INTO _domain FROM semicolony.services WHERE service_id = rec.service_id;
|
|
55
|
+
IF _domain IS NOT NULL THEN
|
|
56
|
+
INSERT INTO semicolony.knowledge_base (domain, key, sub_key, content, created_by, metadata)
|
|
57
|
+
VALUES (
|
|
58
|
+
_domain, 'session', 'conversation/' || rec.session_id,
|
|
59
|
+
'',
|
|
60
|
+
'migration-097',
|
|
61
|
+
jsonb_build_object(
|
|
62
|
+
'session_id', rec.session_id,
|
|
63
|
+
'service_id', rec.service_id,
|
|
64
|
+
'mode', rec.mode,
|
|
65
|
+
'status', rec.status,
|
|
66
|
+
'features', rec.features,
|
|
67
|
+
'slack_channel', rec.slack_channel,
|
|
68
|
+
'slack_thread_ts', rec.slack_thread_ts,
|
|
69
|
+
'created_at', rec.created_at::text
|
|
70
|
+
)
|
|
71
|
+
)
|
|
72
|
+
ON CONFLICT (domain, key, sub_key) DO NOTHING;
|
|
73
|
+
END IF;
|
|
74
|
+
END LOOP;
|
|
75
|
+
END $$;
|
|
76
|
+
|
|
77
|
+
-- 5. 테이블 DROP (자식 테이블 먼저)
|
|
78
|
+
DROP TABLE IF EXISTS semicolony.feature_discovery_sessions CASCADE;
|
|
79
|
+
DROP TABLE IF EXISTS semicolony.feature_conversation_sessions CASCADE;
|
|
80
|
+
DROP TABLE IF EXISTS semicolony.service_research_tasks CASCADE;
|
|
81
|
+
DROP TABLE IF EXISTS semicolony.service_infra_requests CASCADE;
|
|
82
|
+
DROP TABLE IF EXISTS semicolony.service_incidents CASCADE;
|
|
83
|
+
DROP TABLE IF EXISTS semicolony.service_iterations CASCADE;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
-- 098: Phase 2 — service_features(6건), service_materials(33건), 부수 3개 테이블 KB 이식 + DROP
|
|
2
|
+
-- 코드는 이미 KB 기반으로 전환됨 (Phase 2a+2b)
|
|
3
|
+
|
|
4
|
+
-- 1. service_features (6건) → KB feature/{feature_id}
|
|
5
|
+
-- drift 복구: 이미 DROP 된 소스 테이블은 to_regclass 가드로 skip (2026-04-23)
|
|
6
|
+
DO $$
|
|
7
|
+
DECLARE
|
|
8
|
+
rec RECORD;
|
|
9
|
+
_domain TEXT;
|
|
10
|
+
_slug TEXT;
|
|
11
|
+
BEGIN
|
|
12
|
+
IF to_regclass('semicolony.service_features') IS NULL OR to_regclass('semicolony.services') IS NULL THEN
|
|
13
|
+
RAISE NOTICE '098-1 skipped: source tables already dropped';
|
|
14
|
+
RETURN;
|
|
15
|
+
END IF;
|
|
16
|
+
FOR rec IN SELECT * FROM semicolony.service_features LOOP
|
|
17
|
+
SELECT service_domain INTO _domain FROM semicolony.services WHERE service_id = rec.service_id;
|
|
18
|
+
IF _domain IS NOT NULL THEN
|
|
19
|
+
_slug := lower(regexp_replace(rec.name, '[^a-zA-Z0-9가-힣]+', '-', 'g'));
|
|
20
|
+
_slug := regexp_replace(_slug, '^-|-$', '', 'g');
|
|
21
|
+
IF _slug = '' THEN _slug := left(rec.feature_id::text, 8); END IF;
|
|
22
|
+
|
|
23
|
+
INSERT INTO semicolony.knowledge_base (domain, key, sub_key, content, created_by, metadata)
|
|
24
|
+
VALUES (
|
|
25
|
+
_domain, 'feature', rec.feature_id::text,
|
|
26
|
+
COALESCE(rec.description, ''),
|
|
27
|
+
'migration-098',
|
|
28
|
+
jsonb_build_object(
|
|
29
|
+
'feature_id', rec.feature_id,
|
|
30
|
+
'slug', _slug,
|
|
31
|
+
'service_id', rec.service_id,
|
|
32
|
+
'name', rec.name,
|
|
33
|
+
'category', COALESCE(rec.category, 'core'),
|
|
34
|
+
'status', COALESCE(rec.status, 'active'),
|
|
35
|
+
'parent_id', rec.parent_id,
|
|
36
|
+
'sort_order', COALESCE(rec.sort_order, 0),
|
|
37
|
+
'feature_metadata', COALESCE(rec.metadata, '{}'::jsonb),
|
|
38
|
+
'created_at', rec.created_at::text
|
|
39
|
+
)
|
|
40
|
+
)
|
|
41
|
+
ON CONFLICT (domain, key, sub_key) DO NOTHING;
|
|
42
|
+
END IF;
|
|
43
|
+
END LOOP;
|
|
44
|
+
END $$;
|
|
45
|
+
|
|
46
|
+
-- 2. service_materials (33건) → KB material/{material_id}
|
|
47
|
+
DO $$
|
|
48
|
+
DECLARE
|
|
49
|
+
rec RECORD;
|
|
50
|
+
_domain TEXT;
|
|
51
|
+
BEGIN
|
|
52
|
+
IF to_regclass('semicolony.service_materials') IS NULL OR to_regclass('semicolony.services') IS NULL THEN
|
|
53
|
+
RAISE NOTICE '098-2 skipped: source tables already dropped';
|
|
54
|
+
RETURN;
|
|
55
|
+
END IF;
|
|
56
|
+
FOR rec IN SELECT * FROM semicolony.service_materials LOOP
|
|
57
|
+
SELECT service_domain INTO _domain FROM semicolony.services WHERE service_id = rec.service_id;
|
|
58
|
+
IF _domain IS NOT NULL THEN
|
|
59
|
+
INSERT INTO semicolony.knowledge_base (domain, key, sub_key, content, created_by, metadata)
|
|
60
|
+
VALUES (
|
|
61
|
+
_domain, 'material', rec.material_id::text,
|
|
62
|
+
COALESCE(rec.content, ''),
|
|
63
|
+
'migration-098',
|
|
64
|
+
jsonb_build_object(
|
|
65
|
+
'material_id', rec.material_id,
|
|
66
|
+
'service_id', rec.service_id,
|
|
67
|
+
'material_type', COALESCE(rec.material_type, 'planning-doc'),
|
|
68
|
+
'phase_mapping', COALESCE(rec.phase_mapping, 'null'::jsonb),
|
|
69
|
+
'screenshot_data', rec.screenshot_data,
|
|
70
|
+
'stitch_share_url', rec.stitch_share_url,
|
|
71
|
+
'created_at', rec.created_at::text
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
ON CONFLICT (domain, key, sub_key) DO NOTHING;
|
|
75
|
+
END IF;
|
|
76
|
+
END LOOP;
|
|
77
|
+
END $$;
|
|
78
|
+
|
|
79
|
+
-- 3. deploy_verifications → KB deploy-verify/{infra_phase}/{date}
|
|
80
|
+
DO $$
|
|
81
|
+
DECLARE
|
|
82
|
+
rec RECORD;
|
|
83
|
+
_domain TEXT;
|
|
84
|
+
_date TEXT;
|
|
85
|
+
BEGIN
|
|
86
|
+
IF to_regclass('semicolony.deploy_verifications') IS NULL OR to_regclass('semicolony.services') IS NULL THEN
|
|
87
|
+
RAISE NOTICE '098-3 skipped: source tables already dropped';
|
|
88
|
+
RETURN;
|
|
89
|
+
END IF;
|
|
90
|
+
FOR rec IN SELECT * FROM semicolony.deploy_verifications LOOP
|
|
91
|
+
SELECT service_domain INTO _domain FROM semicolony.services WHERE service_id = rec.service_id;
|
|
92
|
+
IF _domain IS NOT NULL THEN
|
|
93
|
+
_date := to_char(rec.created_at, 'YYYY-MM-DD');
|
|
94
|
+
INSERT INTO semicolony.knowledge_base (domain, key, sub_key, content, created_by, metadata)
|
|
95
|
+
VALUES (
|
|
96
|
+
_domain, 'deploy-verify', rec.infra_phase || '/' || _date,
|
|
97
|
+
'',
|
|
98
|
+
'migration-098',
|
|
99
|
+
jsonb_build_object(
|
|
100
|
+
'verification_id', rec.verification_id,
|
|
101
|
+
'service_id', rec.service_id,
|
|
102
|
+
'infra_phase', rec.infra_phase,
|
|
103
|
+
'checks', rec.checks,
|
|
104
|
+
'overall_status', rec.overall_status,
|
|
105
|
+
'verified_by', rec.verified_by,
|
|
106
|
+
'created_at', rec.created_at::text
|
|
107
|
+
)
|
|
108
|
+
)
|
|
109
|
+
ON CONFLICT (domain, key, sub_key) DO NOTHING;
|
|
110
|
+
END IF;
|
|
111
|
+
END LOOP;
|
|
112
|
+
END $$;
|
|
113
|
+
|
|
114
|
+
-- 4. 테이블 DROP
|
|
115
|
+
DROP TABLE IF EXISTS semicolony.feature_status_transitions CASCADE;
|
|
116
|
+
DROP TABLE IF EXISTS semicolony.deploy_verifications CASCADE;
|
|
117
|
+
DROP TABLE IF EXISTS semicolony.service_kpi_metrics CASCADE;
|
|
118
|
+
DROP TABLE IF EXISTS semicolony.service_features CASCADE;
|
|
119
|
+
DROP TABLE IF EXISTS semicolony.service_materials CASCADE;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
-- 099: Phase 3 — service_sections (141건) KB 이식 + DROP
|
|
2
|
+
-- 코드는 이미 KB 기반으로 전환됨 (section/{track}/{phase}/{section_key})
|
|
3
|
+
|
|
4
|
+
-- 1. service_sections → KB section/{track}/{phase}/{section_key}
|
|
5
|
+
-- drift 복구: 이미 DROP 된 소스 테이블은 to_regclass 가드로 skip (2026-04-23)
|
|
6
|
+
DO $$
|
|
7
|
+
DECLARE
|
|
8
|
+
rec RECORD;
|
|
9
|
+
_domain TEXT;
|
|
10
|
+
_sub_key TEXT;
|
|
11
|
+
BEGIN
|
|
12
|
+
IF to_regclass('semicolony.service_sections') IS NULL OR to_regclass('semicolony.services') IS NULL THEN
|
|
13
|
+
RAISE NOTICE '099-1 skipped: source tables already dropped';
|
|
14
|
+
RETURN;
|
|
15
|
+
END IF;
|
|
16
|
+
FOR rec IN SELECT * FROM semicolony.service_sections LOOP
|
|
17
|
+
SELECT service_domain INTO _domain FROM semicolony.services WHERE service_id = rec.service_id;
|
|
18
|
+
IF _domain IS NOT NULL THEN
|
|
19
|
+
_sub_key := COALESCE(rec.track, 'plan') || '/' || rec.phase || '/' || rec.section_key;
|
|
20
|
+
|
|
21
|
+
INSERT INTO semicolony.knowledge_base (domain, key, sub_key, content, created_by, metadata)
|
|
22
|
+
VALUES (
|
|
23
|
+
_domain, 'section', _sub_key,
|
|
24
|
+
COALESCE(rec.content, ''),
|
|
25
|
+
'migration-099',
|
|
26
|
+
jsonb_build_object(
|
|
27
|
+
'section_id', _sub_key,
|
|
28
|
+
'service_id', rec.service_id,
|
|
29
|
+
'phase', rec.phase,
|
|
30
|
+
'track', COALESCE(rec.track, 'plan'),
|
|
31
|
+
'section_key', rec.section_key,
|
|
32
|
+
'title', COALESCE(rec.title, ''),
|
|
33
|
+
'ordinal', COALESCE(rec.ordinal, 0),
|
|
34
|
+
'status', COALESCE(rec.status, 'draft'),
|
|
35
|
+
'source', COALESCE(rec.source, 'manual'),
|
|
36
|
+
'reviewer_note', rec.reviewer_note,
|
|
37
|
+
'qa_items', COALESCE(rec.qa_items, 'null'::jsonb),
|
|
38
|
+
'slack_thread_ts', rec.slack_thread_ts,
|
|
39
|
+
'kb_written_at', rec.kb_written_at::text,
|
|
40
|
+
'created_at', rec.created_at::text
|
|
41
|
+
)
|
|
42
|
+
)
|
|
43
|
+
ON CONFLICT (domain, key, sub_key) DO UPDATE SET
|
|
44
|
+
content = EXCLUDED.content,
|
|
45
|
+
metadata = EXCLUDED.metadata,
|
|
46
|
+
updated_at = NOW();
|
|
47
|
+
END IF;
|
|
48
|
+
END LOOP;
|
|
49
|
+
END $$;
|
|
50
|
+
|
|
51
|
+
-- 2. 테이블 DROP
|
|
52
|
+
DROP TABLE IF EXISTS semicolony.service_sections CASCADE;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- 099: cron-poller-tick 메타 잡 seed
|
|
2
|
+
-- Phase 1 폴러가 매 분 자기 heartbeat 을 mark-run 으로 기록하기 위한 대상.
|
|
3
|
+
-- semiclaw 봇에 FK 매핑, schedule '* * * * *', skip_dispatch 플래그로 tick WHERE 제외.
|
|
4
|
+
|
|
5
|
+
INSERT INTO semicolony.bot_cron_jobs (bot_id, job_id, name, schedule, enabled, payload)
|
|
6
|
+
VALUES (
|
|
7
|
+
'semiclaw',
|
|
8
|
+
'cron-poller-tick',
|
|
9
|
+
'SEMICOLONY cron poller heartbeat',
|
|
10
|
+
'{"kind":"cron","expr":"* * * * *","tz":"Asia/Seoul"}'::jsonb,
|
|
11
|
+
TRUE,
|
|
12
|
+
'{"report_channel":"#bot-ops","skip_dispatch":true,"meta":"cron-poller"}'::jsonb
|
|
13
|
+
)
|
|
14
|
+
ON CONFLICT (bot_id, job_id) DO NOTHING;
|