@team-semicolon/semicolony-cli 4.18.57 → 4.18.59

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.
@@ -0,0 +1,44 @@
1
+ -- 165_skill_release_retirements.sql
2
+ -- governed skill 은퇴 프리미티브: append-only retirement 기록.
3
+ -- 판정: (channel, skill_name)의 최신 retirement.retired_at > 최신 activation.activated_at ⇒ 은퇴.
4
+ -- 재활성화(새 activation)가 은퇴를 해제한다. 어떤 기존 행도 수정/삭제하지 않는다.
5
+
6
+ CREATE TABLE IF NOT EXISTS semicolony.skill_release_retirements (
7
+ retirement_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
8
+ channel text NOT NULL CHECK (NULLIF(btrim(channel), '') IS NOT NULL),
9
+ skill_name text NOT NULL CHECK (skill_name ~ '^[a-z0-9]+(?:-[a-z0-9]+)*$'),
10
+ reason text NOT NULL CHECK (NULLIF(btrim(reason), '') IS NOT NULL),
11
+ lease_id uuid NOT NULL REFERENCES semicolony.skill_capability_leases(lease_id),
12
+ approval_reference text NOT NULL CHECK (NULLIF(btrim(approval_reference), '') IS NOT NULL),
13
+ idempotency_key text NOT NULL UNIQUE CHECK (NULLIF(btrim(idempotency_key), '') IS NOT NULL),
14
+ retired_by_principal text NOT NULL CHECK (NULLIF(btrim(retired_by_principal), '') IS NOT NULL),
15
+ retired_at timestamptz NOT NULL DEFAULT clock_timestamp()
16
+ );
17
+
18
+ CREATE INDEX IF NOT EXISTS skill_release_retirements_lookup
19
+ ON semicolony.skill_release_retirements (channel, skill_name, retired_at DESC);
20
+
21
+ DROP TRIGGER IF EXISTS protect_skill_release_retirements ON semicolony.skill_release_retirements;
22
+ CREATE TRIGGER protect_skill_release_retirements
23
+ BEFORE UPDATE OR DELETE ON semicolony.skill_release_retirements
24
+ FOR EACH ROW EXECUTE FUNCTION semicolony.reject_skill_governance_mutation();
25
+
26
+ CREATE OR REPLACE VIEW semicolony.v_current_skill_release_retirements AS
27
+ SELECT DISTINCT ON (channel, skill_name)
28
+ retirement_id, channel, skill_name, reason, lease_id,
29
+ approval_reference, idempotency_key, retired_by_principal, retired_at
30
+ FROM semicolony.skill_release_retirements
31
+ ORDER BY channel, skill_name, retired_at DESC, retirement_id DESC;
32
+
33
+ REVOKE ALL ON TABLE
34
+ semicolony.skill_release_retirements,
35
+ semicolony.v_current_skill_release_retirements
36
+ FROM PUBLIC, sc_app;
37
+
38
+ GRANT SELECT, INSERT ON TABLE
39
+ semicolony.skill_release_retirements
40
+ TO sc_app;
41
+
42
+ GRANT SELECT ON TABLE
43
+ semicolony.v_current_skill_release_retirements
44
+ TO sc_app;
@@ -0,0 +1,76 @@
1
+ -- 166_lease_operations_retire.sql
2
+ -- 161_skill_governance.sql이 정의한 profile→operations CHECK 제약은 'operate'
3
+ -- 프로필에 허용된 연산을 리터럴 배열로 고정한다. skill-governance.ts의 governed
4
+ -- 은퇴 경로(`skills.release.retire`, operate-only)가 이미 이 연산을 요구하지만
5
+ -- 161의 배열에는 없어 모든 은퇴 리스 발급이 이 CHECK로 거부된다.
6
+ --
7
+ -- 이 제약은 161에서 이름 없이(anonymous) 생성되어 Postgres가 자동 명명한
8
+ -- 이름을 신뢰할 수 없다. pg_constraint에서 정의 텍스트로 대상을 찾아
9
+ -- 안전하게 DROP한 뒤, 동일한 read/make 분기와 skills.release.retire를
10
+ -- 추가한 operate 분기로 NAMED 제약을 재생성한다. 마이그레이션 러너가
11
+ -- 트랜잭션 경계를 제공하므로 BEGIN/COMMIT은 넣지 않는다.
12
+
13
+ ALTER TABLE semicolony.skill_capability_leases
14
+ DROP CONSTRAINT IF EXISTS skill_capability_leases_profile_operations_check;
15
+
16
+ DO $$
17
+ DECLARE
18
+ legacy_conname TEXT;
19
+ BEGIN
20
+ SELECT pg_constraint.conname
21
+ INTO legacy_conname
22
+ FROM pg_constraint
23
+ WHERE pg_constraint.conrelid = 'semicolony.skill_capability_leases'::regclass
24
+ AND pg_constraint.contype = 'c'
25
+ AND pg_get_constraintdef(pg_constraint.oid) LIKE '%skills.release.stage%'
26
+ AND pg_get_constraintdef(pg_constraint.oid) LIKE '%profile%'
27
+ LIMIT 1;
28
+
29
+ IF legacy_conname IS NOT NULL THEN
30
+ EXECUTE format(
31
+ 'ALTER TABLE semicolony.skill_capability_leases DROP CONSTRAINT %I',
32
+ legacy_conname
33
+ );
34
+ END IF;
35
+ END
36
+ $$;
37
+
38
+ ALTER TABLE semicolony.skill_capability_leases
39
+ ADD CONSTRAINT skill_capability_leases_profile_operations_check
40
+ CHECK (
41
+ (
42
+ profile = 'read'
43
+ AND operations <@ ARRAY[
44
+ 'skills.health.read',
45
+ 'skills.release.read'
46
+ ]::TEXT[]
47
+ )
48
+ OR
49
+ (
50
+ profile = 'make'
51
+ AND operations <@ ARRAY[
52
+ 'skills.health.read',
53
+ 'skills.release.read',
54
+ 'skills.proposal.write',
55
+ 'skills.projection.reconcile',
56
+ 'skills.project.write',
57
+ 'skills.release.stage'
58
+ ]::TEXT[]
59
+ )
60
+ OR
61
+ (
62
+ profile = 'operate'
63
+ AND operations <@ ARRAY[
64
+ 'skills.health.read',
65
+ 'skills.release.read',
66
+ 'skills.proposal.write',
67
+ 'skills.projection.reconcile',
68
+ 'skills.project.write',
69
+ 'skills.release.stage',
70
+ 'skills.project.publish',
71
+ 'skills.release.activate',
72
+ 'skills.audience.manage',
73
+ 'skills.release.retire'
74
+ ]::TEXT[]
75
+ )
76
+ );
@@ -14,6 +14,8 @@ SEMICOLONY CLI의 PostgreSQL 마이그레이션 파일들.
14
14
  | `005_bot_workspace_audits.sql` | Bot workspace 감사 테이블 |
15
15
  | `006_bot_kb_subscriptions.sql` | 봇별 KB 구독 테이블 |
16
16
  | `007_flatten_skill_names.sql` | Flat skill naming 마이그레이션 |
17
+ | `165_skill_release_retirements.sql` | 거버넌스 스킬 은퇴 프리미티브 (append-only 기록 + 뷰) |
18
+ | `166_lease_operations_retire.sql` | `skill_capability_leases` profile→operations CHECK 재생성: operate 프로필에 `skills.release.retire` 추가 |
17
19
 
18
20
  ## 007: Flat Skill Naming
19
21
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-semicolon/semicolony-cli",
3
- "version": "4.18.57",
3
+ "version": "4.18.59",
4
4
  "description": "SemiColony CLI - AI operations and agent orchestration installer",
5
5
  "main": "dist/bundle.js",
6
6
  "bin": {