@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,34 @@
|
|
|
1
|
+
-- 110: kb-manager 스킬 프롬프트 L2 leakage 정리
|
|
2
|
+
-- migrations 027/031 가 skill_definitions(name='kb-manager') 의 prompt 에
|
|
3
|
+
-- 'reus' (팀원 닉네임), 'by-buyer' (세미콜론 L2 서비스), 그리고 027 의 경우
|
|
4
|
+
-- '/Users/reus/Desktop/Sources/...' 하드코딩 경로까지 박아 두었다.
|
|
5
|
+
-- 027/031 인라인 텍스트는 일반화 (이 migration 시리즈와 함께 적용),
|
|
6
|
+
-- 기존 인스턴스의 row 는 이 migration 이 정확 매칭일 때만 갱신.
|
|
7
|
+
--
|
|
8
|
+
-- 관련 인벤토리: docs/L2-INVENTORY.md (HIGH — kb-manager skill_definitions row)
|
|
9
|
+
|
|
10
|
+
BEGIN;
|
|
11
|
+
|
|
12
|
+
UPDATE semicolony.skill_definitions
|
|
13
|
+
SET
|
|
14
|
+
prompt = REPLACE(
|
|
15
|
+
REPLACE(
|
|
16
|
+
REPLACE(
|
|
17
|
+
REPLACE(
|
|
18
|
+
REPLACE(prompt,
|
|
19
|
+
'semicolony kb get semicolon team reus', 'semicolony kb get <org> team alice'),
|
|
20
|
+
'semicolony kb get by-buyer po', 'semicolony kb get my-service po'),
|
|
21
|
+
'semicolony kb search "PO" --service by-buyer', 'semicolony kb search "PO" --service my-service'),
|
|
22
|
+
'semicolony kb upsert semicolon decision 2026-03-24/example', 'semicolony kb upsert <org> decision 2026-03-24/example'),
|
|
23
|
+
'export SEMICOLONY_ROOT="/Users/reus/Desktop/Sources/semicolon/projects/semicolony"\ncd $SEMICOLONY_ROOT/packages/cli\n', ''
|
|
24
|
+
),
|
|
25
|
+
updated_at = NOW()
|
|
26
|
+
WHERE name = 'kb-manager'
|
|
27
|
+
AND office_id IS NULL
|
|
28
|
+
AND (
|
|
29
|
+
prompt LIKE '%semicolony kb get semicolon team reus%'
|
|
30
|
+
OR prompt LIKE '%--service by-buyer%'
|
|
31
|
+
OR prompt LIKE '%/Users/reus/Desktop/Sources/semicolon/projects/semicolony%'
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
COMMIT;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- 111: 030 이 시드한 세미콜론 팀원 ontology rows 정리
|
|
2
|
+
-- migration 030 가 OSS fresh install 시 세미콜론 팀원 10명 (reus, garden, roki, yeomso,
|
|
3
|
+
-- bon, kyago, bae, harry, goni, kai) 의 ontology row 를 자동 시드했음.
|
|
4
|
+
-- 030 인라인은 이 migration 시리즈와 함께 INSERT 블록 제거.
|
|
5
|
+
-- 기존 인스턴스에서 이미 시드된 row 는 KB 데이터가 0건일 때만 삭제 (108 과 동일 패턴).
|
|
6
|
+
--
|
|
7
|
+
-- 관련 인벤토리: docs/L2-INVENTORY.md (HIGH — migration 030 team seeds)
|
|
8
|
+
|
|
9
|
+
BEGIN;
|
|
10
|
+
|
|
11
|
+
DELETE FROM semicolony.ontology o
|
|
12
|
+
WHERE o.domain IN (
|
|
13
|
+
'reus','garden','roki','yeomso','bon','kyago','bae','harry','goni','kai'
|
|
14
|
+
)
|
|
15
|
+
AND o.entity_type IN ('team', 'person')
|
|
16
|
+
AND NOT EXISTS (
|
|
17
|
+
SELECT 1 FROM semicolony.knowledge_base kb WHERE kb.domain = o.domain
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
COMMIT;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
-- 112: pipeline 키 스키마 정합화 + role/po 트리거 services 드리프트 복구
|
|
2
|
+
--
|
|
3
|
+
-- 두 이슈 동시 수정:
|
|
4
|
+
-- 1. `semicolony kb upsert <domain> role po` 가 `relation "semicolony.services" does not exist` 로 실패
|
|
5
|
+
-- (migration 072 가 만든 trg_sync_role_po 트리거가 migration 101 에서 DROP 된 services 테이블을 참조)
|
|
6
|
+
-- 2. service 타입 `pipeline` 키가 schema=singleton 이지만 실제 데이터는 sub_key='config' (migration-100 이식 + SoT 문서)
|
|
7
|
+
-- → 신규 도메인 등록 시 sub_key='' 로 들어가 도메인 간 형태 갈라짐
|
|
8
|
+
--
|
|
9
|
+
-- KB 트래킹:
|
|
10
|
+
-- - semicolony process kb-role-upsert-services-drift (2026-04-27)
|
|
11
|
+
-- - semicolony process pipeline-key-schema-sot-mismatch (2026-04-27)
|
|
12
|
+
--
|
|
13
|
+
-- 선행 조건: 111
|
|
14
|
+
|
|
15
|
+
BEGIN;
|
|
16
|
+
|
|
17
|
+
-- ============================================================
|
|
18
|
+
-- 1. role/po 동기화 트리거 재구성: services 테이블 → KB pipeline/config metadata
|
|
19
|
+
-- ============================================================
|
|
20
|
+
-- 기존 트리거는 DROP 된 semicolony.services.owner_name 을 UPDATE 하려 해서 항상 실패.
|
|
21
|
+
-- pipeline/config metadata.owner_name 이 이제 SoT 이므로 그곳을 업데이트한다.
|
|
22
|
+
-- 무한 재귀 방지: pipeline/config 업데이트는 key='role' 조건과 매칭되지 않으므로 트리거 재진입 없음.
|
|
23
|
+
|
|
24
|
+
DROP TRIGGER IF EXISTS trg_sync_role_po ON semicolony.knowledge_base;
|
|
25
|
+
|
|
26
|
+
CREATE OR REPLACE FUNCTION semicolony.sync_role_po_to_owner()
|
|
27
|
+
RETURNS TRIGGER AS $$
|
|
28
|
+
DECLARE
|
|
29
|
+
_owner text;
|
|
30
|
+
BEGIN
|
|
31
|
+
IF NEW.key = 'role' AND NEW.sub_key = 'po' THEN
|
|
32
|
+
_owner := TRIM(SPLIT_PART(NEW.content, ',', 1));
|
|
33
|
+
UPDATE semicolony.knowledge_base
|
|
34
|
+
SET metadata = jsonb_set(COALESCE(metadata, '{}'::jsonb), '{owner_name}', to_jsonb(_owner), true),
|
|
35
|
+
updated_at = NOW()
|
|
36
|
+
WHERE domain = NEW.domain
|
|
37
|
+
AND key = 'pipeline'
|
|
38
|
+
AND sub_key = 'config';
|
|
39
|
+
END IF;
|
|
40
|
+
RETURN NEW;
|
|
41
|
+
END;
|
|
42
|
+
$$ LANGUAGE plpgsql;
|
|
43
|
+
|
|
44
|
+
CREATE TRIGGER trg_sync_role_po
|
|
45
|
+
AFTER INSERT OR UPDATE ON semicolony.knowledge_base
|
|
46
|
+
FOR EACH ROW
|
|
47
|
+
WHEN (NEW.key = 'role' AND NEW.sub_key = 'po')
|
|
48
|
+
EXECUTE FUNCTION semicolony.sync_role_po_to_owner();
|
|
49
|
+
|
|
50
|
+
-- ============================================================
|
|
51
|
+
-- 2. pipeline 키 schema: singleton → collection (sub_key='config' SoT)
|
|
52
|
+
-- ============================================================
|
|
53
|
+
-- 기존 17개 도메인은 sub_key='config' 로 존재 (migration-100).
|
|
54
|
+
-- service-metadata-sot 문서, 글로벌 CLAUDE.md, 코드(channel-router, dashboard 등)
|
|
55
|
+
-- 모두 'pipeline/config' 를 가정. schema 만 어긋나 있어 schema 를 데이터에 맞춘다.
|
|
56
|
+
|
|
57
|
+
UPDATE semicolony.kb_type_schema
|
|
58
|
+
SET key_type = 'collection',
|
|
59
|
+
value_hint = 'sub_key=''config'' 고정. metadata: {service_id, project_name, owner_name, current_phase, infra_phase, status, lifecycle, service_type, parent_service_id, tech_stack, service_url, repo, slack_channel, launched_at, ...}',
|
|
60
|
+
scheme_description = '프로젝트 파이프라인 워크플로우 상태 (sub_key=''config'' 단일 사용)'
|
|
61
|
+
WHERE type_key = 'service'
|
|
62
|
+
AND scheme_key = 'pipeline';
|
|
63
|
+
|
|
64
|
+
-- ============================================================
|
|
65
|
+
-- 3. 신규 등록 도메인 백필: pipeline (sub_key='') → pipeline/config
|
|
66
|
+
-- ============================================================
|
|
67
|
+
-- migration-100 이후 등록되었지만 schema=singleton 강제로 sub_key='' 로 들어간 행을
|
|
68
|
+
-- sub_key='config' 로 이동. 충돌 시(이미 config 가 있으면) sub_key='' 행은 그대로 두고
|
|
69
|
+
-- 사람이 확인 후 정리하도록 남긴다.
|
|
70
|
+
|
|
71
|
+
UPDATE semicolony.knowledge_base AS kb
|
|
72
|
+
SET sub_key = 'config',
|
|
73
|
+
updated_at = NOW()
|
|
74
|
+
WHERE key = 'pipeline'
|
|
75
|
+
AND sub_key = ''
|
|
76
|
+
AND NOT EXISTS (
|
|
77
|
+
SELECT 1 FROM semicolony.knowledge_base kb2
|
|
78
|
+
WHERE kb2.domain = kb.domain
|
|
79
|
+
AND kb2.key = 'pipeline'
|
|
80
|
+
AND kb2.sub_key = 'config'
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
COMMIT;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
-- 113_kb_history.sql
|
|
2
|
+
-- P1-5: KB 변경 이력 — knowledge_base 의 INSERT/UPDATE/DELETE 자동 기록
|
|
3
|
+
--
|
|
4
|
+
-- 목적: context push / kb upsert 가 잘못된 값으로 덮어썼을 때 롤백·감사·diff 분석 가능.
|
|
5
|
+
-- snapshot 형식: kb_snapshot JSONB 에 OLD/NEW 행 통째 직렬화 (스키마 확장에 robust).
|
|
6
|
+
|
|
7
|
+
CREATE TABLE IF NOT EXISTS semicolony.knowledge_base_history (
|
|
8
|
+
history_id BIGSERIAL PRIMARY KEY,
|
|
9
|
+
kb_id BIGINT,
|
|
10
|
+
operation TEXT NOT NULL CHECK (operation IN ('insert', 'update', 'delete')),
|
|
11
|
+
changed_by VARCHAR(100),
|
|
12
|
+
changed_at TIMESTAMPTZ DEFAULT NOW(),
|
|
13
|
+
-- INSERT/DELETE: 해당 행 통째. UPDATE: 변경 전(OLD) 행 통째.
|
|
14
|
+
kb_snapshot JSONB NOT NULL
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE INDEX IF NOT EXISTS idx_kb_history_kb_id
|
|
18
|
+
ON semicolony.knowledge_base_history(kb_id);
|
|
19
|
+
CREATE INDEX IF NOT EXISTS idx_kb_history_changed_at
|
|
20
|
+
ON semicolony.knowledge_base_history(changed_at DESC);
|
|
21
|
+
-- 도메인/키 검색 위해 JSONB 부분 인덱스 (kb_snapshot.domain / .key)
|
|
22
|
+
CREATE INDEX IF NOT EXISTS idx_kb_history_domain_key
|
|
23
|
+
ON semicolony.knowledge_base_history(
|
|
24
|
+
(kb_snapshot->>'domain'),
|
|
25
|
+
(kb_snapshot->>'key')
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
CREATE OR REPLACE FUNCTION semicolony.kb_history_trigger_fn() RETURNS trigger AS $$
|
|
29
|
+
BEGIN
|
|
30
|
+
IF TG_OP = 'INSERT' THEN
|
|
31
|
+
INSERT INTO semicolony.knowledge_base_history(kb_id, operation, changed_by, kb_snapshot)
|
|
32
|
+
VALUES (NEW.kb_id, 'insert', NEW.created_by, to_jsonb(NEW));
|
|
33
|
+
RETURN NEW;
|
|
34
|
+
ELSIF TG_OP = 'UPDATE' THEN
|
|
35
|
+
INSERT INTO semicolony.knowledge_base_history(kb_id, operation, changed_by, kb_snapshot)
|
|
36
|
+
VALUES (OLD.kb_id, 'update', COALESCE(NEW.created_by, OLD.created_by), to_jsonb(OLD));
|
|
37
|
+
RETURN NEW;
|
|
38
|
+
ELSIF TG_OP = 'DELETE' THEN
|
|
39
|
+
INSERT INTO semicolony.knowledge_base_history(kb_id, operation, changed_by, kb_snapshot)
|
|
40
|
+
VALUES (OLD.kb_id, 'delete', OLD.created_by, to_jsonb(OLD));
|
|
41
|
+
RETURN OLD;
|
|
42
|
+
END IF;
|
|
43
|
+
RETURN NULL;
|
|
44
|
+
END;
|
|
45
|
+
$$ LANGUAGE plpgsql;
|
|
46
|
+
|
|
47
|
+
DROP TRIGGER IF EXISTS kb_history_trigger ON semicolony.knowledge_base;
|
|
48
|
+
CREATE TRIGGER kb_history_trigger
|
|
49
|
+
AFTER INSERT OR UPDATE OR DELETE ON semicolony.knowledge_base
|
|
50
|
+
FOR EACH ROW EXECUTE FUNCTION semicolony.kb_history_trigger_fn();
|
|
51
|
+
|
|
52
|
+
COMMENT ON TABLE semicolony.knowledge_base_history IS
|
|
53
|
+
'P1-5: KB 변경 이력. AFTER INSERT/UPDATE/DELETE 트리거로 자동 기록.';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
-- 114_runtime_target_columns.sql
|
|
2
|
+
-- P5-6: ExecutionTarget / Runtime Portable DB 스키마 확장
|
|
3
|
+
--
|
|
4
|
+
-- 봇이 어떤 호스트에서 어떤 모델로 어떤 도구·투사 채널과 결합해 동작할지를
|
|
5
|
+
-- DB SoT 로 표현. 기존 capability 는 packages/common/src/runtime 인터페이스에
|
|
6
|
+
-- 코드로만 있었지만, 봇 인스턴스별 선호/제약은 DB 가 SoT.
|
|
7
|
+
--
|
|
8
|
+
-- 모든 컬럼 nullable — 기존 봇은 변경 없이 동작 (회귀 0).
|
|
9
|
+
|
|
10
|
+
ALTER TABLE semicolony.bot_status
|
|
11
|
+
ADD COLUMN IF NOT EXISTS runtime_hint TEXT[],
|
|
12
|
+
ADD COLUMN IF NOT EXISTS tool_capabilities TEXT[],
|
|
13
|
+
ADD COLUMN IF NOT EXISTS projection_targets JSONB;
|
|
14
|
+
|
|
15
|
+
COMMENT ON COLUMN semicolony.bot_status.runtime_hint IS
|
|
16
|
+
'P5-6: 선호 호스트 우선순위 배열. 예: [''claude-code'', ''codex-cli'', ''ollama-cli'']. RuntimeHarness 가 첫 번째 사용 가능 host 선택.';
|
|
17
|
+
|
|
18
|
+
COMMENT ON COLUMN semicolony.bot_status.tool_capabilities IS
|
|
19
|
+
'P5-6: 봇이 호출 가능한 도구 이름 배열. ToolGateway register 결과와 매칭. 예: [''kb_get'', ''kb_upsert'', ''commitments_create''].';
|
|
20
|
+
|
|
21
|
+
COMMENT ON COLUMN semicolony.bot_status.projection_targets IS
|
|
22
|
+
'P5-6: 기본 투사 타깃 JSONB 배열. 예: [{"channel":"slack-block","destination":"C123","options":{"botId":"semiclaw"}}]. ProjectionEmitter.emitAll 에 전달.';
|
|
23
|
+
|
|
24
|
+
-- 인덱스 — runtime_hint 로 호스트별 봇 조회 자주 발생 시
|
|
25
|
+
CREATE INDEX IF NOT EXISTS idx_bot_status_runtime_hint
|
|
26
|
+
ON semicolony.bot_status USING GIN (runtime_hint);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
-- 115_runtime_source_columns.sql
|
|
2
|
+
-- 2026-05-06: OpenClaw + slack-router 공존 운영 — runtime_source 메타 추가.
|
|
3
|
+
-- Codex review (semicolon-plan-review): "두 운영 루프가 commitments/cron 공유 시
|
|
4
|
+
-- source 구분 필수. 최소값: slack-router | openclaw | manual | cron"
|
|
5
|
+
--
|
|
6
|
+
-- 모든 컬럼 nullable — 회귀 0. 기존 row 는 source_type 기반 추론 backfill.
|
|
7
|
+
|
|
8
|
+
-- ── bot_commitments ──
|
|
9
|
+
ALTER TABLE semicolony.bot_commitments
|
|
10
|
+
ADD COLUMN IF NOT EXISTS runtime_source TEXT;
|
|
11
|
+
|
|
12
|
+
COMMENT ON COLUMN semicolony.bot_commitments.runtime_source IS
|
|
13
|
+
'운영 런타임 출처. slack-router | openclaw | manual | cron. 2026-05-06 추가 (KB semicolony decision/openclaw-architecture-b-coexist).';
|
|
14
|
+
|
|
15
|
+
-- backfill: source_type → runtime_source 추론
|
|
16
|
+
UPDATE semicolony.bot_commitments
|
|
17
|
+
SET runtime_source = CASE
|
|
18
|
+
WHEN source_type = 'slack-inbox' THEN 'slack-router'
|
|
19
|
+
WHEN source_type = 'cron' THEN 'cron'
|
|
20
|
+
WHEN source_type = 'claude-code-local' THEN 'manual'
|
|
21
|
+
WHEN source_type LIKE 'openclaw%' THEN 'openclaw'
|
|
22
|
+
ELSE NULL
|
|
23
|
+
END
|
|
24
|
+
WHERE runtime_source IS NULL;
|
|
25
|
+
|
|
26
|
+
CREATE INDEX IF NOT EXISTS idx_bot_commitments_runtime_source
|
|
27
|
+
ON semicolony.bot_commitments (runtime_source)
|
|
28
|
+
WHERE runtime_source IS NOT NULL;
|
|
29
|
+
|
|
30
|
+
-- ── bot_cron_jobs ──
|
|
31
|
+
ALTER TABLE semicolony.bot_cron_jobs
|
|
32
|
+
ADD COLUMN IF NOT EXISTS runtime_source TEXT;
|
|
33
|
+
|
|
34
|
+
COMMENT ON COLUMN semicolony.bot_cron_jobs.runtime_source IS
|
|
35
|
+
'잡을 fire 하는 런타임. cron(=cron-poller, Architecture B) | openclaw(=OpenClaw 자체 cron) | manual.';
|
|
36
|
+
|
|
37
|
+
-- 기본 backfill: 기존 cron 잡은 cron-poller 가 fan-out 하던 것이므로 'cron'
|
|
38
|
+
UPDATE semicolony.bot_cron_jobs
|
|
39
|
+
SET runtime_source = 'cron'
|
|
40
|
+
WHERE runtime_source IS NULL;
|
|
41
|
+
|
|
42
|
+
-- ── action_items ──
|
|
43
|
+
ALTER TABLE semicolony.action_items
|
|
44
|
+
ADD COLUMN IF NOT EXISTS runtime_source TEXT;
|
|
45
|
+
|
|
46
|
+
COMMENT ON COLUMN semicolony.action_items.runtime_source IS
|
|
47
|
+
'액션 아이템 생성 런타임. slack-router | openclaw | manual | cron.';
|
|
48
|
+
|
|
49
|
+
-- 기본 backfill: 기존 action_item 은 사용자 직접 / 봇이 만든 것이라 'manual'
|
|
50
|
+
UPDATE semicolony.action_items
|
|
51
|
+
SET runtime_source = 'manual'
|
|
52
|
+
WHERE runtime_source IS NULL;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
-- 116_commitment_pattern_health.sql
|
|
2
|
+
-- 2026-05-06: PAL 스타일 패턴 단위 실패 누적 추적 (C3 of Ouroboros adoption).
|
|
3
|
+
-- Ouroboros routing/escalation.py 의 EscalationManager 패턴을 SEMICOLONY 에 변형 차용.
|
|
4
|
+
-- 검증 근거: /tmp/ouroboros-sandbox/evidence/c3_results.json — 실 SEMICOLONY failed
|
|
5
|
+
-- commitment 500개 replay 시 16 escalation + 432 stagnation, 7 cron 패턴이 Frontier
|
|
6
|
+
-- 까지 도달 (cron poller 250x, commitment-watchdog 71x 등 침묵 실패 누적).
|
|
7
|
+
--
|
|
8
|
+
-- 이번 마이그레이션은 추적 스키마만 도입한다. 알림 부수효과(Slack DM, #bot-ops 포스팅)
|
|
9
|
+
-- 는 PR2 에서 슬랙 라우터에 부착. 이 PR 은 신호를 DB 에 적재하고, fail/done 전이에서
|
|
10
|
+
-- 카운터를 갱신하는 데까지만 한다 — 회귀 0.
|
|
11
|
+
|
|
12
|
+
-- ── pattern health 추적 ─────────────────────────────────────────────────────
|
|
13
|
+
CREATE TABLE IF NOT EXISTS semicolony.commitment_pattern_health (
|
|
14
|
+
-- 패턴 키: "{bot_id}::{canonical_prefix}#{hash}".
|
|
15
|
+
-- - canonical_prefix: title 을 NFKC + invisibles strip + whitespace collapse +
|
|
16
|
+
-- lowercase 후 첫 60 code point.
|
|
17
|
+
-- - hash: sha256(canonical title) 의 첫 10 hex — prefix 가 같지만 본문이 다른
|
|
18
|
+
-- title 들을 분리.
|
|
19
|
+
-- 키 생성/정규화 SoT 는 packages/cli/src/commitment-escalation.ts.
|
|
20
|
+
pattern_id TEXT PRIMARY KEY,
|
|
21
|
+
|
|
22
|
+
bot_id TEXT NOT NULL,
|
|
23
|
+
title_prefix TEXT NOT NULL,
|
|
24
|
+
|
|
25
|
+
consecutive_failures INTEGER NOT NULL DEFAULT 0
|
|
26
|
+
CHECK (consecutive_failures >= 0),
|
|
27
|
+
|
|
28
|
+
last_failure_at TIMESTAMPTZ,
|
|
29
|
+
last_success_at TIMESTAMPTZ,
|
|
30
|
+
|
|
31
|
+
-- 에스컬레이션 상태머신: none → notified (2 fails) → paged (5 fails)
|
|
32
|
+
-- 성공 시 즉시 'none' 으로 리셋. 알림 부수효과는 PR2.
|
|
33
|
+
state TEXT NOT NULL DEFAULT 'none'
|
|
34
|
+
CHECK (state IN ('none', 'notified', 'paged')),
|
|
35
|
+
|
|
36
|
+
-- 상태 전환을 마지막으로 관측한 시각. 진단/대시보드용.
|
|
37
|
+
-- ⚠ 알림 dedup 용도로는 신뢰하지 말 것 — 동시 실패 호출 시 두 트랜잭션 모두
|
|
38
|
+
-- "전이 발생" 으로 관측될 수 있다. PR2 에서 별도 claim 컬럼 또는
|
|
39
|
+
-- notification dedup 테이블로 idempotency 를 잡는다.
|
|
40
|
+
state_changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
41
|
+
|
|
42
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
43
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
COMMENT ON TABLE semicolony.commitment_pattern_health IS
|
|
47
|
+
'봇 약속의 (bot_id, title_prefix) 패턴별 연속 실패 누적과 에스컬레이션 상태. '
|
|
48
|
+
'Ouroboros C3 (PAL escalation 변형). 2026-05-06 추가.';
|
|
49
|
+
|
|
50
|
+
COMMENT ON COLUMN semicolony.commitment_pattern_health.pattern_id IS
|
|
51
|
+
'"{bot_id}::{canonical_prefix}#{sha256_10}". canonical = NFKC + invisibles strip + '
|
|
52
|
+
'whitespace collapse + lowercase. SoT: packages/cli/src/commitment-escalation.ts.';
|
|
53
|
+
|
|
54
|
+
COMMENT ON COLUMN semicolony.commitment_pattern_health.state IS
|
|
55
|
+
'none | notified (2회 연속 실패) | paged (5회 연속 실패). '
|
|
56
|
+
'성공 1회로 즉시 none 으로 reset.';
|
|
57
|
+
|
|
58
|
+
-- 활성 escalation 모니터링 인덱스 — paged 상태 패턴이 가장 시급.
|
|
59
|
+
CREATE INDEX IF NOT EXISTS idx_commitment_pattern_health_active_state
|
|
60
|
+
ON semicolony.commitment_pattern_health (state, last_failure_at DESC)
|
|
61
|
+
WHERE state <> 'none';
|
|
62
|
+
|
|
63
|
+
-- bot 별 health 조회 (대시보드용).
|
|
64
|
+
CREATE INDEX IF NOT EXISTS idx_commitment_pattern_health_bot_id
|
|
65
|
+
ON semicolony.commitment_pattern_health (bot_id);
|
|
66
|
+
|
|
67
|
+
-- updated_at 자동 갱신 트리거 — bot_commitments 와 동일 컨벤션.
|
|
68
|
+
CREATE OR REPLACE FUNCTION semicolony.fn_commitment_pattern_health_updated_at()
|
|
69
|
+
RETURNS TRIGGER AS $$
|
|
70
|
+
BEGIN
|
|
71
|
+
NEW.updated_at := NOW();
|
|
72
|
+
RETURN NEW;
|
|
73
|
+
END;
|
|
74
|
+
$$ LANGUAGE plpgsql;
|
|
75
|
+
|
|
76
|
+
DROP TRIGGER IF EXISTS trg_commitment_pattern_health_updated
|
|
77
|
+
ON semicolony.commitment_pattern_health;
|
|
78
|
+
|
|
79
|
+
CREATE TRIGGER trg_commitment_pattern_health_updated
|
|
80
|
+
BEFORE UPDATE ON semicolony.commitment_pattern_health
|
|
81
|
+
FOR EACH ROW EXECUTE FUNCTION semicolony.fn_commitment_pattern_health_updated_at();
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
-- 117_commitment_pattern_alert_claims.sql
|
|
2
|
+
-- 2026-05-06: PR2 of Ouroboros C3 — alert claim 컬럼 추가.
|
|
3
|
+
--
|
|
4
|
+
-- PR1 은 state 전환을 추적했지만 (notified/paged), 동시 실패 호출 시 두 caller
|
|
5
|
+
-- 모두 state_changed=true 를 관측할 수 있다 (CTE old 가 pre-lock 값을 읽음).
|
|
6
|
+
-- 알림 부수효과는 race-safe 가 아니라는 뜻이다.
|
|
7
|
+
--
|
|
8
|
+
-- PR2 는 DB-backed claim 으로 idempotency 를 잡는다:
|
|
9
|
+
-- - notified_at: 'notified' 상태 진입 후 첫 성공한 claim 시각.
|
|
10
|
+
-- - paged_at: 'paged' 상태 진입 후 첫 성공한 claim 시각.
|
|
11
|
+
-- claim 패턴: UPDATE … SET notified_at = NOW() WHERE pattern_id = $1
|
|
12
|
+
-- AND state = 'notified' AND notified_at IS NULL RETURNING …;
|
|
13
|
+
-- 첫 caller 만 row 를 받고 (rowCount=1), 나머지는 0 — 이게 알림 발송 권한.
|
|
14
|
+
--
|
|
15
|
+
-- success 시 (state → 'none') 두 컬럼 모두 NULL 로 reset 해서, 다음 회복-실패
|
|
16
|
+
-- 사이클에서 새 claim 가능.
|
|
17
|
+
|
|
18
|
+
ALTER TABLE semicolony.commitment_pattern_health
|
|
19
|
+
ADD COLUMN IF NOT EXISTS notified_at TIMESTAMPTZ,
|
|
20
|
+
ADD COLUMN IF NOT EXISTS paged_at TIMESTAMPTZ;
|
|
21
|
+
|
|
22
|
+
COMMENT ON COLUMN semicolony.commitment_pattern_health.notified_at IS
|
|
23
|
+
'"notified" 상태 진입 후 첫 알림 claim 시각. 알림 dedup 용 — '
|
|
24
|
+
'UPDATE … WHERE notified_at IS NULL RETURNING 으로 atomic 발송 권한 결정.';
|
|
25
|
+
|
|
26
|
+
COMMENT ON COLUMN semicolony.commitment_pattern_health.paged_at IS
|
|
27
|
+
'"paged" 상태 진입 후 첫 알림 claim 시각. notified_at 와 동일한 dedup 패턴.';
|
|
28
|
+
|
|
29
|
+
-- 미발송 alert 빠르게 찾기.
|
|
30
|
+
CREATE INDEX IF NOT EXISTS idx_commitment_pattern_health_pending_alert
|
|
31
|
+
ON semicolony.commitment_pattern_health (state, last_failure_at DESC)
|
|
32
|
+
WHERE (state = 'notified' AND notified_at IS NULL)
|
|
33
|
+
OR (state = 'paged' AND paged_at IS NULL);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
-- 118_retire_semiclaw_semicolonybot_alias
|
|
2
|
+
--
|
|
3
|
+
-- 2026-04-23 의 migration 104 가 'semiclaw → semicolonybot' 리브랜드 1단계로 alias 를 깔았다.
|
|
4
|
+
-- 그러나 2026-05-06 의사결정(KB: semicolony decision/semicolonybot-independent-agent-2026-05-06)으로
|
|
5
|
+
-- SemiColonyBot 은 SemiClaw 의 후계가 아니라 별 system_guide 에이전트로 분리되었다.
|
|
6
|
+
--
|
|
7
|
+
-- 현재 alias 가 살아 있는 동안에는:
|
|
8
|
+
-- * channel-router 의 모든 'semiclaw' 입력(직접 [Route: semiclaw] / 하드코딩된
|
|
9
|
+
-- orchestrator 폴백 / phase 폴백 등)이 'semicolonybot' 으로 재라우팅된다.
|
|
10
|
+
-- * SemiColonyBot 의 runtime_source 는 'slack-router-system' (persona only, inbox 없음).
|
|
11
|
+
-- * 결과적으로 orchestrator 트래픽이 처리 불능 상태로 빠지는 잠재적 버그.
|
|
12
|
+
--
|
|
13
|
+
-- 본 마이그레이션은 alias 를 retire(soft delete) 한다. 향후 다시 켜고 싶다면
|
|
14
|
+
-- retired_at = NULL 로 되돌리면 된다. 'orphan' 로 보존되는 row 자체는 삭제하지
|
|
15
|
+
-- 않는다 (감사용).
|
|
16
|
+
--
|
|
17
|
+
-- 별 후속 정리 항목 (이 PR 범위 밖):
|
|
18
|
+
-- * SemiColonyBot bot_status row 의 role 을 'orchestrator' → 'system_management' 로 정리
|
|
19
|
+
-- * SemiColonyBot 의 bot_delegation 행들(SemiClaw 복제) 정리 — persona only 이므로 위임 불필요
|
|
20
|
+
-- * SemiColonyBot 의 seat_id (snamanager0) 가 다른 봇에 할당되지 않은 sanity check
|
|
21
|
+
|
|
22
|
+
BEGIN;
|
|
23
|
+
|
|
24
|
+
UPDATE semicolony.bot_id_aliases
|
|
25
|
+
SET retired_at = NOW()
|
|
26
|
+
WHERE alias = 'semiclaw'
|
|
27
|
+
AND canonical_bot_id = 'semicolonybot'
|
|
28
|
+
AND retired_at IS NULL;
|
|
29
|
+
|
|
30
|
+
COMMIT;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
-- 119_commitment_events
|
|
2
|
+
--
|
|
3
|
+
-- Ouroboros C5 — Event Replay (dual-write phase).
|
|
4
|
+
-- 자세한 설계: /tmp/ouroboros-sandbox/evidence/c5_schema_draft.md (action item 4b406bbd)
|
|
5
|
+
-- · taxonomy: 8 종 — commitment_created/status_changed/heartbeat/step_done/
|
|
6
|
+
-- claimed/released/stale_reaped/cron_run_recorded
|
|
7
|
+
-- · idempotency_key UNIQUE — 같은 이벤트 재기록 방지 (재시도 흡수)
|
|
8
|
+
-- · transaction boundary: EscalationQueryable 패턴 (caller 의 client 받아 같이 commit/rollback)
|
|
9
|
+
-- · projector acceptance: 7일 dual-write 동안 divergence=0 이면 read source flip 검토
|
|
10
|
+
-- · write failure policy: best-effort, 원본 mutation 차단하지 않음
|
|
11
|
+
--
|
|
12
|
+
-- 이 마이그레이션은 *append-only* 이벤트 로그를 만들 뿐이며, 기존 bot_commitments
|
|
13
|
+
-- 의 read 경로는 건드리지 않는다. dual-write phase 동안에는 bot_commitments 가
|
|
14
|
+
-- SoT, commitment_events 는 audit/replay 용 redundant write.
|
|
15
|
+
|
|
16
|
+
BEGIN;
|
|
17
|
+
|
|
18
|
+
CREATE TABLE IF NOT EXISTS semicolony.commitment_events (
|
|
19
|
+
event_id BIGSERIAL PRIMARY KEY,
|
|
20
|
+
commitment_id TEXT NOT NULL,
|
|
21
|
+
event_type TEXT NOT NULL CHECK (event_type IN (
|
|
22
|
+
'commitment_created', 'status_changed', 'heartbeat', 'step_done',
|
|
23
|
+
'claimed', 'released', 'stale_reaped', 'cron_run_recorded'
|
|
24
|
+
)),
|
|
25
|
+
payload JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
26
|
+
occurred_at TIMESTAMPTZ NOT NULL,
|
|
27
|
+
recorded_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
28
|
+
bot_id TEXT,
|
|
29
|
+
source_type TEXT,
|
|
30
|
+
runtime_source TEXT,
|
|
31
|
+
idempotency_key TEXT NOT NULL,
|
|
32
|
+
UNIQUE (idempotency_key)
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
CREATE INDEX IF NOT EXISTS idx_commitment_events_by_commitment_time
|
|
36
|
+
ON semicolony.commitment_events (commitment_id, occurred_at);
|
|
37
|
+
|
|
38
|
+
CREATE INDEX IF NOT EXISTS idx_commitment_events_recent
|
|
39
|
+
ON semicolony.commitment_events (recorded_at DESC);
|
|
40
|
+
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_commitment_events_by_bot_recent
|
|
42
|
+
ON semicolony.commitment_events (bot_id, recorded_at DESC)
|
|
43
|
+
WHERE bot_id IS NOT NULL;
|
|
44
|
+
|
|
45
|
+
COMMENT ON TABLE semicolony.commitment_events IS
|
|
46
|
+
'Append-only event log for bot_commitments lifecycle (Ouroboros C5 dual-write phase, migration 119, 2026-05-06). '
|
|
47
|
+
'During dual-write phase, bot_commitments remains read source. After 7+ days '
|
|
48
|
+
'with zero replay divergences, read source flips to events table (separate PR). '
|
|
49
|
+
'Write failures are logged but do not block the original mutation.';
|
|
50
|
+
|
|
51
|
+
COMMIT;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
-- 120_host_signals
|
|
2
|
+
--
|
|
3
|
+
-- BE-1 v2 — host filesystem signal snapshots for /api/system/health.
|
|
4
|
+
-- 액션아이템 3ac42503 의 후속 인프라.
|
|
5
|
+
--
|
|
6
|
+
-- 배경:
|
|
7
|
+
-- semicolony-dashboard (Next.js) 는 OKE Docker pod 안에서 동작 → host 의 pgrep / PID 파일 /
|
|
8
|
+
-- ~/.openclaw-{bot}/auth-profiles.json / log 파일에 직접 접근 불가.
|
|
9
|
+
--
|
|
10
|
+
-- 따라서 v2 는 push 모델로 동작:
|
|
11
|
+
-- 1. host(=Reus Mac mini) 에서 동작하는 sidecar daemon (별 트랙) 이 pgrep/PID/auth
|
|
12
|
+
-- 파일을 주기적으로 스캔
|
|
13
|
+
-- 2. 결과 스냅샷을 이 테이블에 UPSERT
|
|
14
|
+
-- 3. dashboard /api/system/health 는 이 테이블을 읽어 신선한 (recorded_at >
|
|
15
|
+
-- NOW() - 5min) 행만 client 응답에 포함
|
|
16
|
+
--
|
|
17
|
+
-- v1 (DB-only) 와 호환: 이 테이블이 비어있어도 API 는 정상 동작 (host_signals=null/empty).
|
|
18
|
+
|
|
19
|
+
BEGIN;
|
|
20
|
+
|
|
21
|
+
CREATE TABLE IF NOT EXISTS semicolony.host_signals (
|
|
22
|
+
id BIGSERIAL PRIMARY KEY,
|
|
23
|
+
source_host TEXT NOT NULL, -- 예: 'reus-mac-mini' — sidecar self-id
|
|
24
|
+
signal_type TEXT NOT NULL CHECK (signal_type IN (
|
|
25
|
+
'process', -- pgrep 결과 (slack-router/discord-router/openclaw-gateway)
|
|
26
|
+
'pid_file', -- ~/.semicolony/run/*.pid 살아있는 PID
|
|
27
|
+
'auth_profile', -- auth-profiles.json expires + token 형식
|
|
28
|
+
'log_grep', -- 로그 패턴 매칭 (Slack connected/socket failed 등)
|
|
29
|
+
'ancestry' -- ps PPID/TTY 검증 (cmux ancestry 가드와 동일)
|
|
30
|
+
)),
|
|
31
|
+
target_id TEXT NOT NULL, -- bot_id 또는 process 이름 (예: 'slack-router', 'planclaw')
|
|
32
|
+
status TEXT NOT NULL CHECK (status IN ('ok', 'degraded', 'fail', 'expired', 'unknown')),
|
|
33
|
+
payload JSONB NOT NULL DEFAULT '{}'::jsonb, -- pid, ppid, tty, expires_at, log_tail 등 구체적인 값
|
|
34
|
+
observed_at TIMESTAMPTZ NOT NULL, -- sidecar 가 관측한 실제 시점
|
|
35
|
+
recorded_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
36
|
+
expires_at TIMESTAMPTZ, -- 명시적 TTL — 없으면 freshness 만 사용
|
|
37
|
+
UNIQUE (source_host, signal_type, target_id)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
CREATE INDEX IF NOT EXISTS idx_host_signals_recent
|
|
41
|
+
ON semicolony.host_signals (recorded_at DESC);
|
|
42
|
+
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_host_signals_target
|
|
44
|
+
ON semicolony.host_signals (target_id, signal_type, recorded_at DESC);
|
|
45
|
+
|
|
46
|
+
COMMENT ON TABLE semicolony.host_signals IS
|
|
47
|
+
'Host-level filesystem/process signals pushed by sidecar daemons. '
|
|
48
|
+
'semicolony-dashboard reads only — write path is sidecar (host-resident) '
|
|
49
|
+
'because dashboard pod has no host fs/process access. Migration 120, 2026-05-07.';
|
|
50
|
+
|
|
51
|
+
COMMIT;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
-- 121_agent_spec_derived_runtime_metadata
|
|
2
|
+
--
|
|
3
|
+
-- AgentSpec projection metadata for derived/helper bots.
|
|
4
|
+
--
|
|
5
|
+
-- derived_from:
|
|
6
|
+
-- Canonical source bot for derived runtime sessions such as semiclaw-overflow.
|
|
7
|
+
--
|
|
8
|
+
-- reply_as:
|
|
9
|
+
-- Persona/bot id used when a derived runtime should reply as another bot.
|
|
10
|
+
-- Example: semiclaw-overflow has bot_id=semiclaw-overflow but reply_as=semiclaw.
|
|
11
|
+
|
|
12
|
+
BEGIN;
|
|
13
|
+
|
|
14
|
+
ALTER TABLE semicolony.bot_status
|
|
15
|
+
ADD COLUMN IF NOT EXISTS derived_from TEXT REFERENCES semicolony.bot_status(bot_id),
|
|
16
|
+
ADD COLUMN IF NOT EXISTS reply_as TEXT REFERENCES semicolony.bot_status(bot_id);
|
|
17
|
+
|
|
18
|
+
COMMENT ON COLUMN semicolony.bot_status.derived_from IS
|
|
19
|
+
'Source bot id for derived/helper runtime sessions rendered through AgentSpec.';
|
|
20
|
+
|
|
21
|
+
COMMENT ON COLUMN semicolony.bot_status.reply_as IS
|
|
22
|
+
'Bot/persona id to use when a derived runtime replies externally.';
|
|
23
|
+
|
|
24
|
+
INSERT INTO semicolony.bot_status (
|
|
25
|
+
bot_id,
|
|
26
|
+
name,
|
|
27
|
+
emoji,
|
|
28
|
+
role,
|
|
29
|
+
workspace_path,
|
|
30
|
+
status,
|
|
31
|
+
kb_domains,
|
|
32
|
+
budget_per_message,
|
|
33
|
+
slack_username,
|
|
34
|
+
slack_icon_emoji,
|
|
35
|
+
created_by_bot_id,
|
|
36
|
+
template_bot_id,
|
|
37
|
+
runtime_hint,
|
|
38
|
+
tool_capabilities,
|
|
39
|
+
projection_targets,
|
|
40
|
+
derived_from,
|
|
41
|
+
reply_as
|
|
42
|
+
)
|
|
43
|
+
SELECT
|
|
44
|
+
'semiclaw-overflow',
|
|
45
|
+
'SemiClaw Overflow',
|
|
46
|
+
emoji,
|
|
47
|
+
'Derived overflow worker for SemiClaw',
|
|
48
|
+
REPLACE(workspace_path, 'semiclaw', 'semiclaw-overflow'),
|
|
49
|
+
status,
|
|
50
|
+
kb_domains,
|
|
51
|
+
budget_per_message,
|
|
52
|
+
slack_username,
|
|
53
|
+
slack_icon_emoji,
|
|
54
|
+
'__genesis__',
|
|
55
|
+
'semiclaw',
|
|
56
|
+
runtime_hint,
|
|
57
|
+
tool_capabilities,
|
|
58
|
+
projection_targets,
|
|
59
|
+
'semiclaw',
|
|
60
|
+
'semiclaw'
|
|
61
|
+
FROM semicolony.bot_status
|
|
62
|
+
WHERE bot_id = 'semiclaw'
|
|
63
|
+
ON CONFLICT (bot_id) DO UPDATE SET
|
|
64
|
+
derived_from = EXCLUDED.derived_from,
|
|
65
|
+
reply_as = EXCLUDED.reply_as,
|
|
66
|
+
template_bot_id = COALESCE(semicolony.bot_status.template_bot_id, EXCLUDED.template_bot_id);
|
|
67
|
+
|
|
68
|
+
COMMIT;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- 122_agent_spec_derived_fk_policy
|
|
2
|
+
--
|
|
3
|
+
-- Derived/helper bot references must not block retirement/deletion of a source bot.
|
|
4
|
+
-- If the source disappears, the derived runtime falls back to its own identity.
|
|
5
|
+
|
|
6
|
+
BEGIN;
|
|
7
|
+
|
|
8
|
+
ALTER TABLE semicolony.bot_status
|
|
9
|
+
DROP CONSTRAINT IF EXISTS bot_status_derived_from_fkey,
|
|
10
|
+
DROP CONSTRAINT IF EXISTS bot_status_reply_as_fkey;
|
|
11
|
+
|
|
12
|
+
ALTER TABLE semicolony.bot_status
|
|
13
|
+
ADD CONSTRAINT bot_status_derived_from_fkey
|
|
14
|
+
FOREIGN KEY (derived_from) REFERENCES semicolony.bot_status(bot_id) ON DELETE SET NULL,
|
|
15
|
+
ADD CONSTRAINT bot_status_reply_as_fkey
|
|
16
|
+
FOREIGN KEY (reply_as) REFERENCES semicolony.bot_status(bot_id) ON DELETE SET NULL;
|
|
17
|
+
|
|
18
|
+
COMMIT;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
-- 123_agent_spec_projection_skip_targets
|
|
2
|
+
--
|
|
3
|
+
-- Some bot_status rows are helper/runtime support identities, not full projected
|
|
4
|
+
-- OpenClaw/ClaudeCode personas. Keep the policy in bot_status instead of
|
|
5
|
+
-- hardcoding helper names in renderers.
|
|
6
|
+
|
|
7
|
+
BEGIN;
|
|
8
|
+
|
|
9
|
+
ALTER TABLE semicolony.bot_status
|
|
10
|
+
ADD COLUMN IF NOT EXISTS is_helper BOOLEAN NOT NULL DEFAULT FALSE,
|
|
11
|
+
ADD COLUMN IF NOT EXISTS skip_projection_targets TEXT[] NOT NULL DEFAULT '{}';
|
|
12
|
+
|
|
13
|
+
COMMENT ON COLUMN semicolony.bot_status.is_helper IS
|
|
14
|
+
'True for helper/support bot identities that should not be treated as full projected personas.';
|
|
15
|
+
|
|
16
|
+
COMMENT ON COLUMN semicolony.bot_status.skip_projection_targets IS
|
|
17
|
+
'AgentSpec runtime targets to skip for this bot_id. Values: claude-code, codex-skill, openclaw.';
|
|
18
|
+
|
|
19
|
+
UPDATE semicolony.bot_status
|
|
20
|
+
SET is_helper = TRUE,
|
|
21
|
+
skip_projection_targets = ARRAY['openclaw']
|
|
22
|
+
WHERE bot_id = 'kb-sidekick';
|
|
23
|
+
|
|
24
|
+
COMMIT;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
-- P2-C (2026-05-28): bot_commitments 변경 NOTIFY trigger
|
|
2
|
+
-- Dashboard 의 /api/bots/stream SSE handler 가 LISTEN 'semicolony_commitment_change' 로 받음.
|
|
3
|
+
-- Payload: { id, bot_id, status, runtime_source, source_type }
|
|
4
|
+
|
|
5
|
+
CREATE OR REPLACE FUNCTION semicolony.notify_bot_commitment_change()
|
|
6
|
+
RETURNS TRIGGER AS $$
|
|
7
|
+
DECLARE
|
|
8
|
+
payload JSON;
|
|
9
|
+
BEGIN
|
|
10
|
+
payload := json_build_object(
|
|
11
|
+
'op', TG_OP,
|
|
12
|
+
'id', COALESCE(NEW.id, OLD.id),
|
|
13
|
+
'bot_id', COALESCE(NEW.bot_id, OLD.bot_id),
|
|
14
|
+
'status', COALESCE(NEW.status, OLD.status),
|
|
15
|
+
'runtime_source', COALESCE(NEW.runtime_source, OLD.runtime_source),
|
|
16
|
+
'source_type', COALESCE(NEW.source_type, OLD.source_type)
|
|
17
|
+
);
|
|
18
|
+
PERFORM pg_notify('semicolony_commitment_change', payload::text);
|
|
19
|
+
RETURN COALESCE(NEW, OLD);
|
|
20
|
+
END;
|
|
21
|
+
$$ LANGUAGE plpgsql;
|
|
22
|
+
|
|
23
|
+
DROP TRIGGER IF EXISTS trig_bot_commitments_notify ON semicolony.bot_commitments;
|
|
24
|
+
CREATE TRIGGER trig_bot_commitments_notify
|
|
25
|
+
AFTER INSERT OR UPDATE OR DELETE ON semicolony.bot_commitments
|
|
26
|
+
FOR EACH ROW EXECUTE FUNCTION semicolony.notify_bot_commitment_change();
|