@starci/hfs 1.0.1 → 2.0.1
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/CHANGELOG.md +51 -0
- package/README.md +110 -12
- package/bin/hfs.mjs +119 -15
- package/emit/compiler.mjs +35 -0
- package/emit/contracts.mjs +97 -0
- package/emit/operations-worker.mjs +24 -0
- package/emit/operations.mjs +126 -0
- package/emit/schema-worker.mjs +117 -0
- package/emit/static-graph.mjs +670 -0
- package/emit/type-schema.mjs +145 -0
- package/package.json +4 -1
- package/report/sonar.mjs +180 -0
- package/runtime/engine/admission.mjs +284 -0
- package/runtime/engine/digest.mjs +10 -0
- package/runtime/engine/ledger-db.mjs +1245 -0
- package/runtime/engine/machine-db.mjs +1484 -0
- package/runtime/engine/migrations/machine/0001-init.sql +887 -0
- package/runtime/engine/migrations/runtime/0001-init.sql +1072 -0
- package/runtime/engine/migrations/runtime/0003-usage-unavailable.sql +13 -0
- package/runtime/engine/migrations/runtime/0004-attempt-why.sql +43 -0
- package/runtime/engine/plain-object.mjs +5 -0
- package/runtime/knowledge/hfs/canon-pins.yaml +16 -58
- package/runtime/knowledge/hfs/slots.yaml +405 -137
- package/runtime/knowledge/patterns/fe/folder.yaml +309 -0
- package/runtime/knowledge/sonar-gate.yaml +85 -0
- package/runtime/modules/kernel/failure-codes.yaml +1480 -16
- package/runtime/scripts/checks/architecture/backend.mjs +350 -0
- package/runtime/scripts/checks/architecture/background-unowned.mjs +107 -0
- package/runtime/scripts/checks/architecture/client-reaches-server.mjs +94 -0
- package/runtime/scripts/checks/architecture/clones.mjs +200 -0
- package/runtime/scripts/checks/architecture/config-unread.mjs +35 -0
- package/runtime/scripts/checks/architecture/config.mjs +310 -0
- package/runtime/scripts/checks/architecture/connection-map.mjs +208 -0
- package/runtime/scripts/checks/architecture/constructor-deps.mjs +100 -0
- package/runtime/scripts/checks/architecture/contract-fixture-guard.mjs +128 -0
- package/runtime/scripts/checks/architecture/contracts.mjs +792 -0
- package/runtime/scripts/checks/architecture/cross-app-duplicate.mjs +73 -0
- package/runtime/scripts/checks/architecture/dead-exports.mjs +265 -0
- package/runtime/scripts/checks/architecture/default-deny.mjs +129 -0
- package/runtime/scripts/checks/architecture/doc-language.mjs +39 -0
- package/runtime/scripts/checks/architecture/entrypoint.mjs +57 -0
- package/runtime/scripts/checks/architecture/error-codes.mjs +45 -0
- package/runtime/scripts/checks/architecture/error-masked.mjs +60 -0
- package/runtime/scripts/checks/architecture/fe-slot-allows.mjs +38 -0
- package/runtime/scripts/checks/architecture/feature-shape.mjs +49 -0
- package/runtime/scripts/checks/architecture/framework-pinned.mjs +83 -0
- package/runtime/scripts/checks/architecture/frontend.mjs +995 -0
- package/runtime/scripts/checks/architecture/hfs-graph.mjs +61 -0
- package/runtime/scripts/checks/architecture/hfs.mjs +521 -0
- package/runtime/scripts/checks/architecture/hooks-are-hooks.mjs +88 -0
- package/runtime/scripts/checks/architecture/i18n-keys.mjs +146 -0
- package/runtime/scripts/checks/architecture/index.mjs +316 -0
- package/runtime/scripts/checks/architecture/injection-token-exported.mjs +62 -0
- package/runtime/scripts/checks/architecture/machine-ast.mjs +138 -0
- package/runtime/scripts/checks/architecture/module-per-transport.mjs +130 -0
- package/runtime/scripts/checks/architecture/next-data.mjs +775 -0
- package/runtime/scripts/checks/architecture/owners.mjs +89 -0
- package/runtime/scripts/checks/architecture/package-shape.mjs +63 -0
- package/runtime/scripts/checks/architecture/reachability.mjs +233 -0
- package/runtime/scripts/checks/architecture/register-once.mjs +141 -0
- package/runtime/scripts/checks/architecture/registration.mjs +319 -0
- package/runtime/scripts/checks/architecture/required-files.mjs +172 -0
- package/runtime/scripts/checks/architecture/route-files-thin.mjs +97 -0
- package/runtime/scripts/checks/architecture/schema-owner.mjs +261 -0
- package/runtime/scripts/checks/architecture/size-growth.mjs +73 -0
- package/runtime/scripts/checks/architecture/source-names.mjs +607 -0
- package/runtime/scripts/checks/architecture/sql-owner.mjs +142 -0
- package/runtime/scripts/checks/architecture/sql-tokens.mjs +327 -0
- package/runtime/scripts/checks/architecture/symbols.mjs +193 -0
- package/runtime/scripts/checks/architecture/test-world-files.mjs +163 -0
- package/runtime/scripts/checks/architecture/tiers.mjs +130 -0
- package/runtime/scripts/checks/architecture/transport-owner.mjs +112 -0
- package/runtime/scripts/checks/architecture/typescript.mjs +500 -0
- package/runtime/scripts/checks/architecture/unit-spec-providers.mjs +122 -0
- package/runtime/scripts/checks/architecture.mjs +41 -0
- package/runtime/scripts/checks/common.mjs +37 -0
- package/runtime/scripts/checks/typescript-programs.mjs +82 -0
- package/runtime/scripts/lib/artifact-hold.mjs +89 -0
- package/runtime/scripts/lib/artifact-store.mjs +103 -0
- package/runtime/scripts/lib/fs-kind.mjs +10 -0
- package/runtime/scripts/lib/git.mjs +53 -0
- package/runtime/scripts/lib/hfs-allows.mjs +57 -0
- package/runtime/scripts/lib/hfs-check.mjs +254 -28
- package/runtime/scripts/lib/hfs-rules/contract.mjs +126 -0
- package/runtime/scripts/lib/hfs-rules/deps.mjs +63 -0
- package/runtime/scripts/lib/hfs-rules/fe-no-tests.mjs +47 -0
- package/runtime/scripts/lib/hfs-rules/frontend.mjs +124 -0
- package/runtime/scripts/lib/hfs-rules/lint-suppression.mjs +34 -0
- package/runtime/scripts/lib/hfs-rules/pipeline.mjs +51 -0
- package/runtime/scripts/lib/hfs-rules/proof-commands.mjs +64 -0
- package/runtime/scripts/lib/hfs-rules/read.mjs +28 -0
- package/runtime/scripts/lib/hfs-rules/repo-local-checks.mjs +32 -0
- package/runtime/scripts/lib/hfs-rules/secrets.mjs +54 -0
- package/runtime/scripts/lib/hfs-rules/spec-placement.mjs +31 -0
- package/runtime/scripts/lib/hfs-rules/stacks.mjs +54 -0
- package/runtime/scripts/lib/hfs-rules/test-topology.mjs +31 -0
- package/runtime/scripts/lib/hfs-slots.mjs +88 -40
- package/runtime/scripts/lib/hfs-tree.mjs +80 -0
- package/runtime/scripts/lib/hfs-view.mjs +68 -0
- package/runtime/scripts/lib/json.mjs +22 -0
- package/runtime/scripts/lib/language.mjs +107 -0
- package/runtime/scripts/lib/path-key.mjs +2 -0
- package/runtime/scripts/lib/redact.mjs +148 -0
- package/runtime/scripts/lib/repo-identity.mjs +50 -0
- package/runtime/scripts/lib/safe-remove.mjs +179 -0
- package/runtime/scripts/lib/secret-patterns.mjs +44 -0
- package/runtime/scripts/lib/sleep-sync.mjs +17 -0
- package/runtime/scripts/lib/stack-declaration.mjs +52 -0
- package/runtime/scripts/lib/stack-services.mjs +217 -0
- package/runtime/scripts/lib/test-secrets.mjs +120 -0
- package/scaffold/service.mjs +333 -0
- package/sync/format.mjs +46 -0
- package/sync/hygiene.mjs +56 -24
- package/sync/index.mjs +133 -41
- package/sync/managed.mjs +170 -0
- package/sync/skeleton.mjs +32 -10
- package/sync/sonar-key.mjs +13 -0
- package/sync/ts-strict.mjs +48 -0
- package/templates/{common → be/ci-workflows/github/workflows}/ci.yml +13 -13
- package/templates/be/{e2e.yml → ci-workflows/github/workflows/e2e.yml} +1 -0
- package/templates/be/hooks/husky/pre-commit +13 -0
- package/templates/be/hooks/husky/pre-push +7 -0
- package/templates/be/package-scripts/package.json +22 -0
- package/templates/be/{sonar-project.properties → quality-config/sonar-project.properties} +2 -3
- package/templates/be/skeleton/apps/__app__/src/app.module.ts +14 -4
- package/templates/be/skeleton/apps/__app__/src/main.ts +9 -6
- package/templates/be/skeleton/scripts/.gitkeep +0 -0
- package/templates/be/skeleton/src/features/system-health/application/check-liveness.contracts.ts +2 -0
- package/templates/be/skeleton/src/features/system-health/application/check-liveness.handler.ts +22 -0
- package/templates/be/skeleton/src/features/system-health/application/check-liveness.query.ts +11 -0
- package/templates/be/skeleton/src/features/system-health/index.ts +1 -1
- package/templates/be/skeleton/src/features/system-health/system-health.module.ts +3 -3
- package/templates/be/skeleton/src/features/system-health/transport/http/live.controller.ts +8 -9
- package/templates/be/skeleton/src/features/system-health/transport/http/system-health-http.module.ts +3 -6
- package/templates/be/skeleton/src/modules/domain/liveness/index.ts +3 -0
- package/templates/be/skeleton/src/modules/domain/liveness/liveness.contracts.ts +9 -0
- package/templates/be/skeleton/src/modules/domain/liveness/liveness.module-definition.ts +7 -0
- package/templates/be/skeleton/src/modules/domain/liveness/liveness.module.ts +14 -0
- package/templates/be/skeleton/src/modules/domain/liveness/liveness.options.ts +2 -0
- package/templates/be/skeleton/src/modules/domain/liveness/liveness.service.spec.ts +40 -0
- package/templates/be/skeleton/src/modules/domain/liveness/liveness.service.ts +26 -0
- package/templates/be/skeleton/src/modules/platform/clock/clock.decorators.ts +9 -0
- package/templates/be/skeleton/src/modules/platform/clock/clock.module-definition.ts +7 -0
- package/templates/be/skeleton/src/modules/platform/clock/clock.module.ts +19 -0
- package/templates/be/skeleton/src/modules/platform/clock/clock.options.ts +2 -0
- package/templates/be/skeleton/src/modules/platform/clock/clock.port.ts +5 -0
- package/templates/be/skeleton/src/modules/platform/clock/index.ts +4 -0
- package/templates/be/skeleton/src/modules/platform/clock/system-clock.service.spec.ts +20 -0
- package/templates/be/skeleton/src/modules/platform/clock/system-clock.service.ts +9 -0
- package/templates/be/skeleton/src/modules/platform/composition/composition.decorators.ts +8 -0
- package/templates/be/skeleton/src/modules/platform/composition/index.ts +2 -0
- package/templates/be/skeleton/src/modules/platform/config/config.decorators.ts +9 -0
- package/templates/be/skeleton/src/modules/platform/config/index.ts +2 -3
- package/templates/be/skeleton/src/modules/platform/config/server.config.ts +1 -1
- package/templates/be/skeleton/src/modules/platform/config/server.options.ts +0 -3
- package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.contracts.ts +5 -0
- package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.decorators.ts +9 -0
- package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.handler.ts +27 -0
- package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.log-events.ts +5 -0
- package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.module-definition.ts +7 -0
- package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.module.ts +18 -0
- package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.options.ts +2 -0
- package/templates/be/skeleton/src/modules/platform/cqrs/index.ts +4 -0
- package/templates/be/skeleton/src/modules/platform/errors/error.filter.ts +8 -12
- package/templates/be/skeleton/src/modules/platform/errors/errors.log-events.ts +5 -0
- package/templates/be/skeleton/src/modules/platform/errors/index.ts +1 -1
- package/templates/be/skeleton/src/modules/platform/logging/index.ts +4 -4
- package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.spec.ts +99 -0
- package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.ts +38 -0
- package/templates/be/skeleton/src/modules/platform/logging/logging.decorators.ts +9 -0
- package/templates/be/skeleton/src/modules/platform/logging/logging.log-events.ts +7 -0
- package/templates/be/skeleton/src/modules/platform/logging/logging.module-definition.ts +7 -0
- package/templates/be/skeleton/src/modules/platform/logging/logging.module.ts +23 -10
- package/templates/be/skeleton/src/modules/platform/logging/logging.options.ts +2 -0
- package/templates/be/skeleton/src/modules/platform/logging/logging.port.ts +15 -0
- package/templates/be/tool-config/eslint.config.mjs +3 -0
- package/templates/be/tool-config/jest.config.js +1 -0
- package/templates/be/tool-config/prettierignore +8 -0
- package/templates/be/tool-config/prettierrc +1 -0
- package/templates/be/tool-config/src/tests/tsconfig.json +5 -0
- package/templates/be/tool-config/tsconfig.build.json +5 -0
- package/templates/be/tool-config/tsconfig.json +11 -0
- package/templates/common/gitignore.base +1 -1
- package/templates/fe/ci-workflows/github/workflows/ci.yml +54 -0
- package/templates/fe/hooks/husky/pre-commit +16 -0
- package/templates/fe/hooks/husky/pre-push +6 -0
- package/templates/fe/package-scripts/package.json +17 -0
- package/templates/fe/parts/api-client.ts +44 -0
- package/templates/fe/parts/api-outcome.ts +7 -0
- package/templates/fe/quality-config/sonar-project.properties +8 -0
- package/templates/fe/skeleton/apps/__app__/src/app/[locale]/layout.tsx +1 -1
- package/templates/fe/skeleton/apps/__app__/src/app/[locale]/not-found.tsx +1 -1
- package/templates/fe/skeleton/apps/__app__/src/app/global-error.tsx +1 -1
- package/templates/fe/skeleton/scripts/.gitkeep +0 -0
- package/templates/fe/skeleton-app/apps/__app__/src/modules/api/client.ts +1 -0
- package/templates/fe/skeleton-app/apps/__app__/src/modules/api/index.ts +3 -0
- package/templates/fe/skeleton-app/apps/__app__/src/modules/api/outcome.ts +1 -0
- package/templates/fe/skeleton-app/apps/__app__/src/modules/i18n/index.ts +4 -0
- package/templates/fe/skeleton-shared/apps/__app__/next.config.ts +12 -0
- package/templates/fe/skeleton-shared/apps/__app__/src/modules/api/index.ts +2 -0
- package/templates/fe/skeleton-shared/apps/__app__/src/modules/i18n/index.ts +9 -0
- package/templates/fe/skeleton-shared/apps/__app__/src/modules/i18n/request.ts +5 -0
- package/templates/fe/skeleton-shared/apps/__app__/src/proxy.ts +5 -0
- package/templates/fe/skeleton-shared/packages/__family__-api/package.json +12 -0
- package/templates/fe/skeleton-shared/packages/__family__-api/src/client.ts +1 -0
- package/templates/fe/skeleton-shared/packages/__family__-api/src/index.ts +3 -0
- package/templates/fe/skeleton-shared/packages/__family__-api/src/outcome.ts +1 -0
- package/templates/fe/skeleton-shared/packages/__family__-api/tsconfig.json +5 -0
- package/templates/fe/skeleton-shared/packages/__family__-i18n/package.json +18 -0
- package/templates/fe/skeleton-shared/packages/__family__-i18n/src/app.ts +19 -0
- package/templates/fe/skeleton-shared/packages/__family__-i18n/src/index.ts +2 -0
- package/templates/fe/skeleton-shared/packages/__family__-i18n/src/proxy.ts +12 -0
- package/templates/fe/skeleton-shared/packages/__family__-i18n/src/request.ts +15 -0
- package/templates/fe/skeleton-shared/packages/__family__-i18n/tsconfig.json +5 -0
- package/templates/fe/tool-config/eslint.config.mjs +3 -0
- package/templates/fe/tool-config/prettierignore +10 -0
- package/templates/fe/tool-config/prettierrc +1 -0
- package/templates/fe/tool-config/stylelint.config.mjs +3 -0
- package/templates/fe/tool-config/tsconfig.json +4 -0
- package/templates/be/pre-commit +0 -8
- package/templates/be/skeleton/apps/__app__/src/__app__.composition.spec.ts +0 -31
- package/templates/be/skeleton/src/features/system-health/transport/http/live.controller.spec.ts +0 -13
- package/templates/be/skeleton/src/modules/platform/config/env-source.spec.ts +0 -36
- package/templates/be/skeleton/src/modules/platform/config/server.config.spec.ts +0 -19
- package/templates/be/skeleton/src/modules/platform/errors/domain-error.spec.ts +0 -15
- package/templates/be/skeleton/src/modules/platform/errors/error.filter.spec.ts +0 -38
- package/templates/be/skeleton/src/modules/platform/logging/json-logger.spec.ts +0 -33
- package/templates/be/skeleton/src/modules/platform/logging/json-logger.ts +0 -35
- package/templates/be/skeleton/src/modules/platform/logging/log-id.ts +0 -9
- package/templates/be/skeleton/src/modules/platform/logging/logger.port.ts +0 -19
- package/templates/common/codecov.yml +0 -13
- package/templates/common/pre-push +0 -5
- package/templates/fe/e2e.yml +0 -22
- package/templates/fe/pre-commit +0 -7
- package/templates/fe/skeleton/apps/__app__/src/app/health/live/route.spec.ts +0 -10
- package/templates/fe/skeleton/apps/__app__/src/modules/i18n/messages.spec.ts +0 -27
- package/templates/fe/skeleton/apps/__app__/src/modules/i18n/routing.spec.ts +0 -10
- package/templates/fe/sonar-project.properties +0 -11
- /package/templates/be/skeleton/src/modules/platform/config/{env-source.ts → env-source.config.ts} +0 -0
- /package/templates/be/skeleton/src/modules/platform/errors/{domain-error.ts → domain.error.ts} +0 -0
- /package/templates/fe/{skeleton → skeleton-app}/apps/__app__/next.config.ts +0 -0
- /package/templates/fe/{skeleton → skeleton-app}/apps/__app__/src/modules/i18n/config.ts +0 -0
- /package/templates/fe/{skeleton → skeleton-app}/apps/__app__/src/modules/i18n/navigation.ts +0 -0
- /package/templates/fe/{skeleton → skeleton-app}/apps/__app__/src/modules/i18n/request.ts +0 -0
- /package/templates/fe/{skeleton → skeleton-app}/apps/__app__/src/modules/i18n/routing.ts +0 -0
- /package/templates/fe/{skeleton → skeleton-app}/apps/__app__/src/proxy.ts +0 -0
|
@@ -0,0 +1,887 @@
|
|
|
1
|
+
-- ############################################################################################################
|
|
2
|
+
-- PHẦN B — machine.sqlite (mỗi máy) → engine/migrations/machine/0001-init.sql
|
|
3
|
+
-- Gộp: machine.sqlite cũ, reconciler.sqlite, ledger Supervisor, journal.sqlite (mồ côi), mọi JSON state và log văn bản.
|
|
4
|
+
-- ############################################################################################################
|
|
5
|
+
|
|
6
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
7
|
+
-- B0. Danh tính, từ vựng, registry, catalog, archive
|
|
8
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
9
|
+
-- machine_meta: host_id, schema='starci/machine@1', created_at, blob_root, runtime_rev, sqlite_version, node_version.
|
|
10
|
+
CREATE TABLE IF NOT EXISTS machine_meta(key TEXT PRIMARY KEY, value TEXT NOT NULL) STRICT;
|
|
11
|
+
CREATE TABLE IF NOT EXISTS schema_migrations(
|
|
12
|
+
version INTEGER PRIMARY KEY, name TEXT NOT NULL, runtime_rev TEXT, sql_sha256 TEXT NOT NULL,
|
|
13
|
+
backup_path TEXT, backup_sha256 TEXT, started_at INTEGER NOT NULL, finished_at INTEGER,
|
|
14
|
+
status TEXT NOT NULL CHECK(status IN ('running','done','failed'))) STRICT;
|
|
15
|
+
|
|
16
|
+
CREATE TABLE IF NOT EXISTS ui_states(
|
|
17
|
+
ui TEXT PRIMARY KEY CHECK(ui IN ('bad','warn','running','waiting','ok','done','unknown')),
|
|
18
|
+
rank INTEGER NOT NULL, label_vi TEXT NOT NULL) STRICT;
|
|
19
|
+
INSERT OR IGNORE INTO ui_states VALUES
|
|
20
|
+
('bad',0,'Hỏng / Kẹt'),('warn',1,'Chậm / Cảnh báo'),('running',2,'Đang chạy'),('waiting',3,'Chờ'),
|
|
21
|
+
('ok',4,'Ổn'),('done',5,'Xong'),('unknown',6,'Chưa rõ');
|
|
22
|
+
CREATE TABLE IF NOT EXISTS ui_state_map(
|
|
23
|
+
entity TEXT NOT NULL, native TEXT NOT NULL, ui TEXT NOT NULL REFERENCES ui_states(ui), PRIMARY KEY(entity,native)) STRICT;
|
|
24
|
+
INSERT OR IGNORE INTO ui_state_map VALUES
|
|
25
|
+
('service','healthy','ok'),('service','ok','ok'),('service','live','ok'),('service','down','bad'),('service','dead','bad'),
|
|
26
|
+
('service','quarantined','bad'),('service','stale','bad'),('service','restarting','warn'),('service','booting','running'),
|
|
27
|
+
('seat','empty','waiting'),('seat','parked','done'),('seat','booting','running'),('seat','live','ok'),('seat','busy','running'),
|
|
28
|
+
('seat','stale','bad'),('seat','dead','bad'),('seat','replacing','warn'),('seat','quarantined','bad'),('service','degraded','warn'),
|
|
29
|
+
('engine-action','fenced','warn'),('push','failed','bad'),
|
|
30
|
+
('sla','running','waiting'),('sla','violated','warn'),('sla','violated-critical','bad'),('sla','cleared','done'),
|
|
31
|
+
('engine-action','intent','running'),('engine-action','running','running'),('engine-action','done','done'),
|
|
32
|
+
('engine-action','failed','bad'),('engine-action','unknown','bad'),
|
|
33
|
+
('land','queued','waiting'),('land','running','running'),('land','passed','done'),('land','failed','bad'),
|
|
34
|
+
('land','conflict','bad'),('land','refused','bad'),('land','cancelled','done'),
|
|
35
|
+
('push','pushed','done'),('push','skipped','waiting'),('push','refused','bad'),
|
|
36
|
+
('lane','open','running'),('lane','landing','running'),('lane','landed','done'),('lane','abandoned','done'),('lane','removed','done'),
|
|
37
|
+
('provider','healthy','ok'),('provider','recovered','ok'),('provider','striking','warn'),('provider','unavailable','bad'),
|
|
38
|
+
('throttle','normal','ok'),('throttle','heavy','warn'),('throttle','critical','bad'),
|
|
39
|
+
('sup-job','queued','waiting'),('sup-job','spawning','running'),('sup-job','running','running'),('sup-job','reported','running'),
|
|
40
|
+
('sup-job','landing','running'),('sup-job','succeeded','done'),('sup-job','failed','bad'),('sup-job','cancelled','done'),
|
|
41
|
+
('decision','open','waiting'),('decision','claimed','running'),('decision','escalated','warn'),('decision','expired','warn'),
|
|
42
|
+
('decision','resolved','done'),('decision','superseded','done'),
|
|
43
|
+
('owed','open','waiting'),('owed','acked','running'),('owed','closed','done'),
|
|
44
|
+
('gc-run','running','running'),('gc-run','done','done'),('gc-run','errors','warn'),
|
|
45
|
+
('env-server','starting','running'),('env-server','ready','ok'),('env-server','failed','bad'),('env-server','stopped','done'),
|
|
46
|
+
('ask','open','waiting'),('ask','answered','done'),('ask','retired','done'),('ask','expired','warn');
|
|
47
|
+
|
|
48
|
+
CREATE TABLE IF NOT EXISTS blob_ref_columns(
|
|
49
|
+
table_name TEXT NOT NULL, column_name TEXT NOT NULL, PRIMARY KEY(table_name,column_name)) STRICT;
|
|
50
|
+
INSERT OR IGNORE INTO blob_ref_columns VALUES
|
|
51
|
+
('lanes','report_sha'),('land_runs','stdout_sha'),('land_runs','stderr_sha'),
|
|
52
|
+
('engine_actions','result_sha'),('engine_actions','stdout_sha'),('engine_actions','stderr_sha'),
|
|
53
|
+
('metrics_snapshots','data_sha'),('sup_reports','report_sha'),('sup_attempts','prompt_sha'),('sup_attempts','transcript_sha'),
|
|
54
|
+
('env_servers','log_sha'),('notifications','media_sha'),('agent_sessions','transcript_sha'),('sup_events','payload_sha'),
|
|
55
|
+
('seat_transcript_snapshots','sha256'),('pushes','stdout_sha'),('pushes','stderr_sha'),('gc_runs','report_sha');
|
|
56
|
+
|
|
57
|
+
-- ledgers: sổ đăng ký DUY NHẤT mọi runtime.sqlite (reconciler, GC, harness đọc từ đây; bỏ config.yaml supervisor.repos).
|
|
58
|
+
CREATE TABLE IF NOT EXISTS ledgers(
|
|
59
|
+
ledger_id TEXT PRIMARY KEY, -- = meta.ledger_id trong file (UUID)
|
|
60
|
+
name TEXT NOT NULL UNIQUE, -- 'nivo-backend'
|
|
61
|
+
product TEXT,
|
|
62
|
+
repo_root TEXT NOT NULL,
|
|
63
|
+
file TEXT NOT NULL,
|
|
64
|
+
state TEXT NOT NULL DEFAULT 'active' CHECK(state IN ('active','idle','retired')),
|
|
65
|
+
schema_version INTEGER,
|
|
66
|
+
registered_at INTEGER NOT NULL,
|
|
67
|
+
seen_at INTEGER NOT NULL, -- lần engine mở được gần nhất (G16)
|
|
68
|
+
retired_at INTEGER, retired_reason TEXT,
|
|
69
|
+
CHECK(state<>'retired' OR retired_at IS NOT NULL)) STRICT;
|
|
70
|
+
|
|
71
|
+
CREATE TABLE IF NOT EXISTS repositories(
|
|
72
|
+
repo_root TEXT PRIMARY KEY,
|
|
73
|
+
name TEXT NOT NULL,
|
|
74
|
+
role TEXT NOT NULL CHECK(role IN ('backend','frontend','service','runtime')),
|
|
75
|
+
ledger_id TEXT REFERENCES ledgers(ledger_id),
|
|
76
|
+
default_branch TEXT, remote TEXT,
|
|
77
|
+
seen_at INTEGER NOT NULL) STRICT;
|
|
78
|
+
|
|
79
|
+
-- agents / models: HÌNH CHIẾU modules/models/*.yaml (YAML vẫn là hợp đồng), viết lại mỗi lần engine khởi động.
|
|
80
|
+
CREATE TABLE IF NOT EXISTS agents(
|
|
81
|
+
agent TEXT PRIMARY KEY CHECK(agent IN ('devin','codex','claude')),
|
|
82
|
+
provider TEXT, spawn_card TEXT, cli_name TEXT,
|
|
83
|
+
source_rev TEXT NOT NULL, loaded_at INTEGER NOT NULL) STRICT;
|
|
84
|
+
CREATE TABLE IF NOT EXISTS models(
|
|
85
|
+
profile TEXT PRIMARY KEY,
|
|
86
|
+
agent TEXT REFERENCES agents(agent),
|
|
87
|
+
model TEXT, pool TEXT, max_parallel INTEGER, share_pct REAL,
|
|
88
|
+
roles_json TEXT CHECK(roles_json IS NULL OR json_valid(roles_json)),
|
|
89
|
+
cost_json TEXT CHECK(cost_json IS NULL OR json_valid(cost_json)),
|
|
90
|
+
source_rev TEXT NOT NULL, loaded_at INTEGER NOT NULL) STRICT;
|
|
91
|
+
|
|
92
|
+
CREATE TABLE IF NOT EXISTS blobs(
|
|
93
|
+
sha256 TEXT PRIMARY KEY CHECK(length(sha256)=64), bytes INTEGER NOT NULL CHECK(bytes>=0), media_type TEXT NOT NULL,
|
|
94
|
+
encoding TEXT CHECK(encoding IS NULL OR encoding='gzip'), redaction TEXT CHECK(redaction IS NULL OR redaction IN ('v1','binary')),
|
|
95
|
+
file_uri TEXT NOT NULL, http_path TEXT GENERATED ALWAYS AS ('/api/blob/' || sha256) VIRTUAL,
|
|
96
|
+
created_at INTEGER NOT NULL, pinned INTEGER NOT NULL DEFAULT 0 CHECK(pinned IN (0,1)),
|
|
97
|
+
archived_at INTEGER, archive_ref TEXT) STRICT;
|
|
98
|
+
|
|
99
|
+
-- archives: mọi zip/bản sao ở D:/starci-archive (purge, backup DB, retention blob, lane logs) đã kiểm chứng.
|
|
100
|
+
CREATE TABLE IF NOT EXISTS archives(
|
|
101
|
+
archive_path TEXT PRIMARY KEY,
|
|
102
|
+
kind TEXT NOT NULL CHECK(kind IN ('workflow-purge','db-backup','blob-retention','lane-logs','agent-sessions')),
|
|
103
|
+
subject TEXT,
|
|
104
|
+
bytes INTEGER NOT NULL, sha256 TEXT NOT NULL, manifest_sha256 TEXT, entries INTEGER,
|
|
105
|
+
integrity TEXT, -- 'ok' từ integrity_check (db-backup) / 'sha-verified' (zip)
|
|
106
|
+
created_at INTEGER NOT NULL, verified_at INTEGER, expires_at INTEGER) STRICT;
|
|
107
|
+
|
|
108
|
+
-- gc_marks: tập sha đang sống, GC mark theo TỪNG ledger (mở read-only lần lượt, đọc blob_ref_columns của ledger đó)
|
|
109
|
+
-- rồi machine; sweep chỉ xoá file khi: không có trong gc_marks của lượt, pinned=0 ở mọi DB, archived_at IS NOT NULL,
|
|
110
|
+
-- created_at < now-24h. Không ATTACH-UNION (giới hạn 10 DB).
|
|
111
|
+
CREATE TABLE IF NOT EXISTS gc_marks(
|
|
112
|
+
run_id INTEGER NOT NULL REFERENCES gc_runs(run_id) ON DELETE CASCADE,
|
|
113
|
+
sha256 TEXT NOT NULL,
|
|
114
|
+
source TEXT NOT NULL, -- ledger name | 'machine'
|
|
115
|
+
pinned INTEGER NOT NULL DEFAULT 0 CHECK(pinned IN (0,1)),
|
|
116
|
+
PRIMARY KEY(run_id,sha256,source)) STRICT, WITHOUT ROWID;
|
|
117
|
+
|
|
118
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
119
|
+
-- B1. Supervisor (bảng riêng tiền tố sup_; ghế ở `seats`, log ở `machine_logs`, chi phí ở `llm_usage`)
|
|
120
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
121
|
+
CREATE TABLE IF NOT EXISTS sup_jobs(
|
|
122
|
+
job_id TEXT PRIMARY KEY,
|
|
123
|
+
trace_id TEXT NOT NULL CHECK(length(trace_id)=32),
|
|
124
|
+
kind TEXT NOT NULL, -- runtime.fix | runtime.review | ...
|
|
125
|
+
role TEXT NOT NULL CHECK(role IN ('worker','supervisor')),
|
|
126
|
+
cluster TEXT,
|
|
127
|
+
title TEXT NOT NULL,
|
|
128
|
+
status TEXT NOT NULL CHECK(status IN ('queued','spawning','running','reported','landing','succeeded','failed','cancelled')),
|
|
129
|
+
lane TEXT,
|
|
130
|
+
files_json TEXT CHECK(files_json IS NULL OR json_valid(files_json)), -- đường .claude được phép sửa
|
|
131
|
+
brief TEXT,
|
|
132
|
+
payload_json TEXT CHECK(payload_json IS NULL OR json_valid(payload_json)),
|
|
133
|
+
created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL) STRICT;
|
|
134
|
+
CREATE INDEX IF NOT EXISTS ix_sup_jobs_status ON sup_jobs(status,created_at);
|
|
135
|
+
|
|
136
|
+
CREATE TABLE IF NOT EXISTS sup_leases(
|
|
137
|
+
path TEXT PRIMARY KEY,
|
|
138
|
+
job_id TEXT NOT NULL REFERENCES sup_jobs(job_id) ON DELETE CASCADE,
|
|
139
|
+
acquired_at INTEGER NOT NULL, expires_at INTEGER NOT NULL) STRICT;
|
|
140
|
+
|
|
141
|
+
-- sup_attempts: cùng nhóm cột với op_attempts (ai, ở đâu, khi nào, kết quả, tái lập) để không trôi lệch.
|
|
142
|
+
CREATE TABLE IF NOT EXISTS sup_attempts(
|
|
143
|
+
attempt_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
144
|
+
job_id TEXT NOT NULL REFERENCES sup_jobs(job_id) ON DELETE CASCADE,
|
|
145
|
+
dispatch_seq INTEGER NOT NULL DEFAULT 1,
|
|
146
|
+
span_id TEXT NOT NULL CHECK(length(span_id)=16), parent_span_id TEXT,
|
|
147
|
+
agent TEXT CHECK(agent IS NULL OR agent IN ('devin','codex','claude')),
|
|
148
|
+
provider TEXT, model TEXT, effort TEXT, terminal_handle TEXT, worker_pid INTEGER,
|
|
149
|
+
runtime_rev TEXT, cli_name TEXT, cli_version TEXT,
|
|
150
|
+
prompt_sha TEXT REFERENCES blobs(sha256), transcript_sha TEXT REFERENCES blobs(sha256),
|
|
151
|
+
worktree_path TEXT, branch TEXT, base_sha TEXT, head_sha TEXT, landed_sha TEXT,
|
|
152
|
+
spawned_at INTEGER, reported_at INTEGER, acked_at INTEGER, landed_at INTEGER, cancelled_at INTEGER, closed_at INTEGER,
|
|
153
|
+
report_outcome TEXT, verdict TEXT, failure_class TEXT,
|
|
154
|
+
tokens_in INTEGER, tokens_out INTEGER, cost_usd REAL,
|
|
155
|
+
UNIQUE(job_id,dispatch_seq)) STRICT;
|
|
156
|
+
|
|
157
|
+
CREATE TABLE IF NOT EXISTS sup_reports(
|
|
158
|
+
report_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
159
|
+
attempt_id INTEGER NOT NULL UNIQUE REFERENCES sup_attempts(attempt_id) ON DELETE CASCADE,
|
|
160
|
+
job_id TEXT NOT NULL,
|
|
161
|
+
outcome TEXT NOT NULL,
|
|
162
|
+
report_json TEXT NOT NULL CHECK(json_valid(report_json)),
|
|
163
|
+
summary TEXT GENERATED ALWAYS AS (json_extract(report_json,'$.summary')) VIRTUAL,
|
|
164
|
+
report_sha TEXT REFERENCES blobs(sha256), -- <lane>.REPORT.md
|
|
165
|
+
consumed_at INTEGER, created_at INTEGER NOT NULL) STRICT;
|
|
166
|
+
|
|
167
|
+
-- sup_events: nhật ký kiểm toán Supervisor; digest tính trong writer JS như events.
|
|
168
|
+
CREATE TABLE IF NOT EXISTS sup_events(
|
|
169
|
+
seq INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
170
|
+
event_id TEXT NOT NULL UNIQUE,
|
|
171
|
+
entity_type TEXT NOT NULL, entity_id TEXT NOT NULL, kind TEXT NOT NULL, span_id TEXT,
|
|
172
|
+
payload_json TEXT CHECK(payload_json IS NULL OR (json_valid(payload_json) AND length(payload_json)<=16384)),
|
|
173
|
+
payload_sha TEXT REFERENCES blobs(sha256),
|
|
174
|
+
prev_digest TEXT, digest TEXT NOT NULL CHECK(length(digest)=64), created_at INTEGER NOT NULL) STRICT;
|
|
175
|
+
CREATE INDEX IF NOT EXISTS ix_sup_events_kind ON sup_events(kind,seq);
|
|
176
|
+
CREATE INDEX IF NOT EXISTS ix_sup_events_entity ON sup_events(entity_type,entity_id,seq);
|
|
177
|
+
CREATE TRIGGER IF NOT EXISTS sup_events_append_only BEFORE UPDATE ON sup_events BEGIN
|
|
178
|
+
SELECT RAISE(ABORT,'sup_events are append-only');
|
|
179
|
+
END;
|
|
180
|
+
|
|
181
|
+
CREATE TABLE IF NOT EXISTS sup_decision_items(
|
|
182
|
+
di_id TEXT PRIMARY KEY,
|
|
183
|
+
-- MB-07: '<kind>:<entity>:<chữ ký lỗi>:<head>' — không phần rỗng (push-refused thiếu head đã gộp 73 lần vào DI cũ).
|
|
184
|
+
idempotency_key TEXT NOT NULL UNIQUE CHECK(idempotency_key NOT LIKE '%::%' AND idempotency_key NOT LIKE '%:'
|
|
185
|
+
AND idempotency_key NOT LIKE ':%' AND length(idempotency_key)>=5),
|
|
186
|
+
key_parts_json TEXT NOT NULL CHECK(json_valid(key_parts_json) AND json_type(key_parts_json)='object'),
|
|
187
|
+
superseded_by TEXT REFERENCES sup_decision_items(di_id),
|
|
188
|
+
delivered_at INTEGER, -- MB-02: đã báo tới ghế Supervisor chưa (chi tiết ở deliveries)
|
|
189
|
+
ledger_id TEXT REFERENCES ledgers(ledger_id),
|
|
190
|
+
workflow_id TEXT,
|
|
191
|
+
kind TEXT NOT NULL, -- cap-starved | quota-exhausted | runtime-defect | cross-workflow | deadlock | ...
|
|
192
|
+
decider TEXT NOT NULL CHECK(decider IN ('supervisor','owner')),
|
|
193
|
+
entity_type TEXT, entity_id TEXT,
|
|
194
|
+
summary TEXT NOT NULL,
|
|
195
|
+
status TEXT NOT NULL CHECK(status IN ('open','claimed','resolved','escalated','expired','superseded')),
|
|
196
|
+
opened_by TEXT NOT NULL, opened_at INTEGER NOT NULL, due_at INTEGER,
|
|
197
|
+
escalate_to TEXT, escalations INTEGER NOT NULL DEFAULT 0,
|
|
198
|
+
claim_by TEXT, claim_at INTEGER, claim_ttl_ms INTEGER,
|
|
199
|
+
resolved_by TEXT, resolved_at INTEGER, resolution_verb TEXT, decision_id TEXT,
|
|
200
|
+
evidence_json TEXT CHECK(evidence_json IS NULL OR json_valid(evidence_json)),
|
|
201
|
+
options_json TEXT CHECK(options_json IS NULL OR json_valid(options_json)),
|
|
202
|
+
allowed_verbs_json TEXT CHECK(allowed_verbs_json IS NULL OR json_valid(allowed_verbs_json)),
|
|
203
|
+
payload_json TEXT NOT NULL CHECK(json_valid(payload_json))) STRICT;
|
|
204
|
+
CREATE INDEX IF NOT EXISTS ix_sup_di_open ON sup_decision_items(status,due_at);
|
|
205
|
+
|
|
206
|
+
CREATE TABLE IF NOT EXISTS sup_decisions(
|
|
207
|
+
decision_id TEXT PRIMARY KEY, di_id TEXT REFERENCES sup_decision_items(di_id), decider TEXT NOT NULL,
|
|
208
|
+
span_id TEXT NOT NULL CHECK(length(span_id)=16), parent_span_id TEXT,
|
|
209
|
+
ledger_id TEXT, workflow_id TEXT, subject_type TEXT, subject_id TEXT,
|
|
210
|
+
choice TEXT NOT NULL, rationale TEXT, result_json TEXT CHECK(result_json IS NULL OR json_valid(result_json)),
|
|
211
|
+
decided_at INTEGER NOT NULL) STRICT;
|
|
212
|
+
|
|
213
|
+
CREATE TABLE IF NOT EXISTS sup_owed(
|
|
214
|
+
owed_id TEXT PRIMARY KEY,
|
|
215
|
+
kind TEXT NOT NULL, subject TEXT NOT NULL, cluster TEXT,
|
|
216
|
+
state TEXT NOT NULL CHECK(state IN ('open','acked','closed')),
|
|
217
|
+
opened_at INTEGER NOT NULL, due_at INTEGER, acked_at INTEGER, acked_by TEXT, closed_at INTEGER,
|
|
218
|
+
detail_json TEXT CHECK(detail_json IS NULL OR json_valid(detail_json))) STRICT;
|
|
219
|
+
CREATE INDEX IF NOT EXISTS ix_sup_owed_open ON sup_owed(state,due_at);
|
|
220
|
+
|
|
221
|
+
CREATE TABLE IF NOT EXISTS sup_learning(
|
|
222
|
+
item_id TEXT PRIMARY KEY,
|
|
223
|
+
kind TEXT NOT NULL CHECK(kind IN ('lesson','hypothesis','experiment','experiment-result','proposal','owner-feedback','leftover')),
|
|
224
|
+
parent_id TEXT REFERENCES sup_learning(item_id),
|
|
225
|
+
title TEXT NOT NULL, state TEXT, source_ref TEXT, lane TEXT, landed_sha TEXT,
|
|
226
|
+
detail_json TEXT CHECK(detail_json IS NULL OR json_valid(detail_json)),
|
|
227
|
+
created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL) STRICT;
|
|
228
|
+
|
|
229
|
+
CREATE TABLE IF NOT EXISTS sup_owner_rulings(
|
|
230
|
+
ruling_id TEXT PRIMARY KEY, said_at INTEGER NOT NULL, channel TEXT, verbatim TEXT NOT NULL, paraphrase TEXT,
|
|
231
|
+
applies_to TEXT, contract_ref TEXT, recorded_by TEXT, created_at INTEGER NOT NULL) STRICT;
|
|
232
|
+
|
|
233
|
+
CREATE TABLE IF NOT EXISTS sup_bridges(
|
|
234
|
+
bridge_id TEXT PRIMARY KEY, ledger_id TEXT REFERENCES ledgers(ledger_id),
|
|
235
|
+
action TEXT NOT NULL CHECK(action IN ('bridge','transfer','rewire')),
|
|
236
|
+
state TEXT NOT NULL, approved_by TEXT, detail_json TEXT CHECK(detail_json IS NULL OR json_valid(detail_json)),
|
|
237
|
+
created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL) STRICT;
|
|
238
|
+
|
|
239
|
+
CREATE TABLE IF NOT EXISTS sup_messages(
|
|
240
|
+
msg_id TEXT PRIMARY KEY,
|
|
241
|
+
direction TEXT NOT NULL CHECK(direction IN ('in','out')),
|
|
242
|
+
channel TEXT NOT NULL CHECK(channel IN ('telegram','tell','ask-gateway')),
|
|
243
|
+
chat_id TEXT, message_id TEXT, from_ref TEXT, to_ref TEXT, via TEXT,
|
|
244
|
+
text TEXT NOT NULL,
|
|
245
|
+
ok INTEGER CHECK(ok IS NULL OR ok IN (0,1)),
|
|
246
|
+
read_at INTEGER, at INTEGER NOT NULL) STRICT;
|
|
247
|
+
CREATE INDEX IF NOT EXISTS ix_sup_messages_unread ON sup_messages(direction,read_at,at);
|
|
248
|
+
|
|
249
|
+
CREATE TABLE IF NOT EXISTS sup_signals(
|
|
250
|
+
scope TEXT NOT NULL CHECK(scope IN ('supervisor-enabled','supervisor-busy')), key TEXT NOT NULL,
|
|
251
|
+
holder_pid INTEGER, token TEXT, value_json TEXT CHECK(value_json IS NULL OR json_valid(value_json)),
|
|
252
|
+
at INTEGER NOT NULL, expires_at INTEGER, PRIMARY KEY(scope,key)) STRICT;
|
|
253
|
+
|
|
254
|
+
-- llm_usage (máy): chi phí của Supervisor và [Worker].
|
|
255
|
+
CREATE TABLE IF NOT EXISTS llm_usage(
|
|
256
|
+
usage_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
257
|
+
subject_type TEXT NOT NULL CHECK(subject_type IN ('supervisor-turn','worker-attempt')),
|
|
258
|
+
sup_attempt_id INTEGER REFERENCES sup_attempts(attempt_id) ON DELETE CASCADE,
|
|
259
|
+
turn_ref TEXT, span_id TEXT,
|
|
260
|
+
provider TEXT NOT NULL, request_model TEXT, response_model TEXT,
|
|
261
|
+
input_tokens INTEGER, output_tokens INTEGER, cache_read_tokens INTEGER, cache_write_tokens INTEGER, reasoning_tokens INTEGER,
|
|
262
|
+
cost_usd REAL, turns INTEGER, tool_calls INTEGER, tool_errors INTEGER,
|
|
263
|
+
source TEXT NOT NULL CHECK(source IN ('cli-transcript','provider-report')),
|
|
264
|
+
at INTEGER NOT NULL,
|
|
265
|
+
CHECK((subject_type='worker-attempt' AND sup_attempt_id IS NOT NULL) OR (subject_type='supervisor-turn' AND turn_ref IS NOT NULL))) STRICT;
|
|
266
|
+
CREATE INDEX IF NOT EXISTS ix_musage ON llm_usage(subject_type,at);
|
|
267
|
+
|
|
268
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
269
|
+
-- B2. Engine reconciler (thay reconciler.sqlite, reconciler-starts.json, reconciler.heartbeat)
|
|
270
|
+
-- Nguyên tắc (LOG-AUDIT-MACHINE §5): mọi thứ có thời lượng là lịch sử APPEND-ONLY; "trạng thái hiện tại" là view
|
|
271
|
+
-- hoặc một dòng mỏng. Không DELETE, không ghi đè lịch sử. Mọi hành động có id; mọi hệ quả tham chiếu id đó.
|
|
272
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
273
|
+
-- process_runs (G1, MB-04): MỖI tiến trình dài của runtime (engine, harness, gateway, tunnel, telegram-bridge, settler,
|
|
274
|
+
-- push-mains, land) một dòng: sinh ra vì sao, chết vì sao, ai giết, heartbeat cuối lúc chết.
|
|
275
|
+
CREATE TABLE IF NOT EXISTS process_runs(
|
|
276
|
+
run_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
277
|
+
role TEXT NOT NULL CHECK(role IN ('engine','harness','gateway','tunnel','telegram-bridge','settler','push','land','boot','other')),
|
|
278
|
+
pid INTEGER NOT NULL, host TEXT, rev TEXT, epoch INTEGER,
|
|
279
|
+
parent_action_id TEXT, -- engine_actions.id đã sinh ra nó (nếu có)
|
|
280
|
+
start_reason TEXT NOT NULL CHECK(start_reason IN ('boot','ensure-stale-heartbeat','self-reload','crash-restart','manual','scheduled','action')),
|
|
281
|
+
started_at INTEGER NOT NULL,
|
|
282
|
+
last_heartbeat_at INTEGER,
|
|
283
|
+
draining_since INTEGER, -- MB-04: đang bàn giao; ensure KHÔNG giết tiến trình đang drain
|
|
284
|
+
ended_at INTEGER,
|
|
285
|
+
exit_code INTEGER,
|
|
286
|
+
exit_reason TEXT CHECK(exit_reason IS NULL OR exit_reason IN ('clean','reload-handover','crash','killed','lost-lease','stopped','unknown')),
|
|
287
|
+
killed_by TEXT, -- 'boot-ensure' | 'supervisor' | 'owner' | pid:<n>
|
|
288
|
+
heartbeat_age_at_end_ms INTEGER,
|
|
289
|
+
CHECK(ended_at IS NULL OR exit_reason IS NOT NULL)) STRICT;
|
|
290
|
+
CREATE INDEX IF NOT EXISTS ix_process_runs ON process_runs(role,started_at);
|
|
291
|
+
-- Chỉ được điền các trường kết thúc một lần (append-only về ngữ nghĩa).
|
|
292
|
+
CREATE TRIGGER IF NOT EXISTS process_runs_end_once BEFORE UPDATE OF ended_at, exit_reason, killed_by ON process_runs
|
|
293
|
+
WHEN OLD.ended_at IS NOT NULL BEGIN
|
|
294
|
+
SELECT RAISE(ABORT,'process run already ended');
|
|
295
|
+
END;
|
|
296
|
+
CREATE TRIGGER IF NOT EXISTS process_runs_no_delete BEFORE DELETE ON process_runs
|
|
297
|
+
WHEN OLD.started_at > CAST(unixepoch('subsec')*1000 AS INTEGER) - 7776000000 BEGIN -- chỉ GC xoá dòng > 90 ngày
|
|
298
|
+
SELECT RAISE(ABORT,'process_runs are append-only (90-day retention)');
|
|
299
|
+
END;
|
|
300
|
+
-- Tương thích UI-API (/api/reconciler starts24h): các lần engine khởi động = view.
|
|
301
|
+
CREATE VIEW IF NOT EXISTS v_engine_starts AS
|
|
302
|
+
SELECT run_id, started_at AS at, pid, rev, epoch, start_reason AS reason, ended_at, exit_reason, killed_by
|
|
303
|
+
FROM process_runs WHERE role='engine';
|
|
304
|
+
|
|
305
|
+
-- engine_leader: một dòng hiện tại (fence). Lịch sử ở leader_history.
|
|
306
|
+
CREATE TABLE IF NOT EXISTS engine_leader(
|
|
307
|
+
name TEXT PRIMARY KEY, holder TEXT NOT NULL, pid INTEGER NOT NULL, epoch INTEGER NOT NULL,
|
|
308
|
+
process_run_id INTEGER REFERENCES process_runs(run_id),
|
|
309
|
+
heartbeat_at INTEGER NOT NULL, expires_at INTEGER NOT NULL, rev TEXT,
|
|
310
|
+
draining INTEGER NOT NULL DEFAULT 0 CHECK(draining IN (0,1)), -- MB-04: lease vẫn gia hạn bằng timer riêng khi drain
|
|
311
|
+
passes INTEGER, last_pass_ms INTEGER, last_error TEXT) STRICT;
|
|
312
|
+
-- leader_history (G2): mỗi epoch một dòng; giữ lead bao lâu, nhả vì sao.
|
|
313
|
+
CREATE TABLE IF NOT EXISTS leader_history(
|
|
314
|
+
epoch INTEGER PRIMARY KEY,
|
|
315
|
+
holder TEXT NOT NULL, pid INTEGER NOT NULL, process_run_id INTEGER REFERENCES process_runs(run_id), rev TEXT,
|
|
316
|
+
acquired_at INTEGER NOT NULL,
|
|
317
|
+
acquired_how TEXT NOT NULL CHECK(acquired_how IN ('fresh','takeover-stale','handover')),
|
|
318
|
+
released_at INTEGER,
|
|
319
|
+
release_reason TEXT CHECK(release_reason IS NULL OR release_reason IN ('reload','lost','killed','stop','crash'))) STRICT;
|
|
320
|
+
CREATE TRIGGER IF NOT EXISTS leader_history_release_once BEFORE UPDATE ON leader_history
|
|
321
|
+
WHEN OLD.released_at IS NOT NULL OR NEW.epoch<>OLD.epoch OR NEW.acquired_at<>OLD.acquired_at BEGIN
|
|
322
|
+
SELECT RAISE(ABORT,'leader_history is append-only');
|
|
323
|
+
END;
|
|
324
|
+
CREATE TRIGGER IF NOT EXISTS leader_history_no_delete BEFORE DELETE ON leader_history BEGIN
|
|
325
|
+
SELECT RAISE(ABORT,'leader_history is append-only');
|
|
326
|
+
END;
|
|
327
|
+
|
|
328
|
+
CREATE TABLE IF NOT EXISTS engine_cursors(
|
|
329
|
+
ledger_id TEXT PRIMARY KEY REFERENCES ledgers(ledger_id), last_seq INTEGER NOT NULL, updated_at INTEGER NOT NULL) STRICT;
|
|
330
|
+
CREATE TABLE IF NOT EXISTS engine_queue(
|
|
331
|
+
controller TEXT NOT NULL, key TEXT NOT NULL, due_at INTEGER, reason TEXT, tries INTEGER NOT NULL DEFAULT 0,
|
|
332
|
+
last_error TEXT, PRIMARY KEY(controller,key)) STRICT;
|
|
333
|
+
|
|
334
|
+
-- schedules (MB-01): lịch chạy của mọi nhiệm vụ định kỳ nằm trong DB, KHÔNG trong RAM — engine mới đọc lại, không
|
|
335
|
+
-- "first run" lặp (housekeeping 1 lần/ngày từng chạy 32 lần trong 3,5 giờ).
|
|
336
|
+
CREATE TABLE IF NOT EXISTS schedules(
|
|
337
|
+
controller TEXT NOT NULL CHECK(controller IN ('job','workflow','resource','host','gc','fleet','learning','sla')),
|
|
338
|
+
duty TEXT NOT NULL, -- housekeeping, sweep, push, digest, backup, blob-sweep, transcripts, boot ...
|
|
339
|
+
interval_ms INTEGER NOT NULL CHECK(interval_ms>0),
|
|
340
|
+
last_started_at INTEGER, last_finished_at INTEGER,
|
|
341
|
+
last_result TEXT CHECK(last_result IS NULL OR last_result IN ('done','failed','unknown','skipped')),
|
|
342
|
+
last_action_id TEXT, -- engine_actions.id
|
|
343
|
+
last_result_digest TEXT,
|
|
344
|
+
next_due_at INTEGER NOT NULL,
|
|
345
|
+
running_pid INTEGER, -- một lượt đang chạy (không chồng lượt)
|
|
346
|
+
PRIMARY KEY(controller,duty)) STRICT;
|
|
347
|
+
|
|
348
|
+
-- engine_actions (MB-03): kết quả KHÔNG bị cắt 4000 ký tự — result_json chỉ là tóm tắt nhỏ có cấu trúc; bản đầy đủ,
|
|
349
|
+
-- stdout và stderr của verb con là blob. id TẤT ĐỊNH = sha(controller, key, verb, epoch, observed_generation).
|
|
350
|
+
CREATE TABLE IF NOT EXISTS engine_actions(
|
|
351
|
+
id TEXT PRIMARY KEY,
|
|
352
|
+
controller TEXT NOT NULL CHECK(controller IN ('job','workflow','resource','host','gc','fleet','learning','sla')),
|
|
353
|
+
duty TEXT, -- schedules.duty khi hành động là một lượt định kỳ
|
|
354
|
+
key TEXT, verb TEXT, argv_digest TEXT, epoch INTEGER, observed_generation INTEGER,
|
|
355
|
+
span_id TEXT CHECK(span_id IS NULL OR length(span_id)=16), trace_id TEXT,
|
|
356
|
+
state TEXT NOT NULL CHECK(state IN ('intent','running','done','failed','unknown','fenced')),
|
|
357
|
+
mode TEXT CHECK(mode IS NULL OR mode IN ('shadow','active')),
|
|
358
|
+
ledger_id TEXT, workflow_id TEXT, job_id TEXT, attempt_id INTEGER,
|
|
359
|
+
request_id TEXT, -- api_requests.request_id của verb con
|
|
360
|
+
child_run_id INTEGER REFERENCES process_runs(run_id),
|
|
361
|
+
started_at INTEGER, finished_at INTEGER, exit_code INTEGER,
|
|
362
|
+
result_json TEXT CHECK(result_json IS NULL OR (json_valid(result_json) AND length(result_json)<=8192)),
|
|
363
|
+
result_sha TEXT REFERENCES blobs(sha256), -- kết quả đầy đủ
|
|
364
|
+
stdout_sha TEXT REFERENCES blobs(sha256),
|
|
365
|
+
stderr_sha TEXT REFERENCES blobs(sha256), -- stderr ĐẦY ĐỦ (hôm nay cắt 6 dòng)
|
|
366
|
+
error_signature TEXT) STRICT; -- chữ ký lỗi ổn định (không chứa HEAD) để gộp/so lặp
|
|
367
|
+
CREATE INDEX IF NOT EXISTS ix_engine_actions_ctl ON engine_actions(controller,started_at);
|
|
368
|
+
CREATE INDEX IF NOT EXISTS ix_engine_actions_entity ON engine_actions(ledger_id,workflow_id,job_id);
|
|
369
|
+
CREATE INDEX IF NOT EXISTS ix_engine_actions_sig ON engine_actions(controller,error_signature);
|
|
370
|
+
-- action_steps (G13): bước bên trong một hành động dài.
|
|
371
|
+
CREATE TABLE IF NOT EXISTS action_steps(
|
|
372
|
+
action_id TEXT NOT NULL REFERENCES engine_actions(id) ON DELETE CASCADE,
|
|
373
|
+
step_no INTEGER NOT NULL, step TEXT NOT NULL, started_at INTEGER NOT NULL, ms INTEGER,
|
|
374
|
+
ok INTEGER CHECK(ok IS NULL OR ok IN (0,1)), detail TEXT,
|
|
375
|
+
PRIMARY KEY(action_id,step_no)) STRICT;
|
|
376
|
+
|
|
377
|
+
-- controller_modes: mode hiện tại; mode_changes (G6): lịch sử append-only, ai đổi và vì sao.
|
|
378
|
+
CREATE TABLE IF NOT EXISTS controller_modes(
|
|
379
|
+
controller TEXT PRIMARY KEY CHECK(controller IN ('job','workflow','resource','host','gc','fleet','learning')),
|
|
380
|
+
mode TEXT NOT NULL CHECK(mode IN ('off','shadow','active')), set_at INTEGER, set_by TEXT) STRICT;
|
|
381
|
+
CREATE TABLE IF NOT EXISTS mode_changes(
|
|
382
|
+
change_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
383
|
+
controller TEXT NOT NULL, from_mode TEXT, to_mode TEXT NOT NULL CHECK(to_mode IN ('off','shadow','active')),
|
|
384
|
+
by TEXT NOT NULL, reason TEXT NOT NULL, at INTEGER NOT NULL) STRICT;
|
|
385
|
+
CREATE TRIGGER IF NOT EXISTS mode_changes_append_only BEFORE UPDATE ON mode_changes BEGIN
|
|
386
|
+
SELECT RAISE(ABORT,'mode_changes are append-only');
|
|
387
|
+
END;
|
|
388
|
+
CREATE TRIGGER IF NOT EXISTS controller_modes_recorded BEFORE UPDATE OF mode ON controller_modes
|
|
389
|
+
WHEN NEW.mode<>OLD.mode AND NOT EXISTS(SELECT 1 FROM mode_changes c WHERE c.controller=NEW.controller AND c.to_mode=NEW.mode
|
|
390
|
+
AND c.change_id=(SELECT max(change_id) FROM mode_changes WHERE controller=NEW.controller)) BEGIN
|
|
391
|
+
SELECT RAISE(ABORT,'mode change must be recorded in mode_changes first');
|
|
392
|
+
END;
|
|
393
|
+
|
|
394
|
+
-- sla_episodes (G3): MỖI đợt đồng hồ SLA một dòng, APPEND-ONLY. Không DELETE, không ghi đè: chỉ điền violated_at,
|
|
395
|
+
-- reported_at, cleared_at (+ clear_reason) đúng một lần. Đồng hồ đang mở = v_sla_open.
|
|
396
|
+
CREATE TABLE IF NOT EXISTS sla_episodes(
|
|
397
|
+
episode_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
398
|
+
entity TEXT NOT NULL, state TEXT NOT NULL, code TEXT NOT NULL, -- READY_UNDISPATCHED, WORKER_SILENT, SEAT_DEAF, TRANSCRIPT_MISSING ...
|
|
399
|
+
severity TEXT NOT NULL CHECK(severity IN ('warn','critical')),
|
|
400
|
+
ledger_id TEXT, workflow_id TEXT,
|
|
401
|
+
entered_at INTEGER NOT NULL, sla_ms INTEGER NOT NULL,
|
|
402
|
+
violated_at INTEGER, reported_at INTEGER, di_id TEXT,
|
|
403
|
+
cleared_at INTEGER,
|
|
404
|
+
clear_reason TEXT CHECK(clear_reason IS NULL OR clear_reason IN ('resolved','superseded','entity-gone','workflow-stopped')),
|
|
405
|
+
CHECK(cleared_at IS NULL OR clear_reason IS NOT NULL)) STRICT;
|
|
406
|
+
CREATE UNIQUE INDEX IF NOT EXISTS ux_sla_open ON sla_episodes(entity,state) WHERE cleared_at IS NULL; -- một đợt mở / (entity,state)
|
|
407
|
+
CREATE INDEX IF NOT EXISTS ix_sla_code ON sla_episodes(code,entered_at);
|
|
408
|
+
CREATE TRIGGER IF NOT EXISTS sla_episodes_fill_once BEFORE UPDATE ON sla_episodes
|
|
409
|
+
WHEN NEW.entity<>OLD.entity OR NEW.state<>OLD.state OR NEW.code<>OLD.code OR NEW.entered_at<>OLD.entered_at
|
|
410
|
+
OR (OLD.violated_at IS NOT NULL AND NEW.violated_at IS NOT OLD.violated_at)
|
|
411
|
+
OR (OLD.reported_at IS NOT NULL AND NEW.reported_at IS NOT OLD.reported_at)
|
|
412
|
+
OR (OLD.cleared_at IS NOT NULL AND NEW.cleared_at IS NOT OLD.cleared_at) BEGIN
|
|
413
|
+
SELECT RAISE(ABORT,'sla_episodes are append-only: fields fill once');
|
|
414
|
+
END;
|
|
415
|
+
CREATE TRIGGER IF NOT EXISTS sla_episodes_no_delete BEFORE DELETE ON sla_episodes BEGIN
|
|
416
|
+
SELECT RAISE(ABORT,'sla_episodes are append-only');
|
|
417
|
+
END;
|
|
418
|
+
|
|
419
|
+
CREATE TABLE IF NOT EXISTS invariant_violations(
|
|
420
|
+
violation_id INTEGER PRIMARY KEY AUTOINCREMENT, code TEXT NOT NULL,
|
|
421
|
+
severity TEXT NOT NULL CHECK(severity IN ('warn','critical')),
|
|
422
|
+
entity TEXT NOT NULL, ledger_id TEXT, workflow_id TEXT, episode_id INTEGER REFERENCES sla_episodes(episode_id),
|
|
423
|
+
violated_at INTEGER NOT NULL, cleared_at INTEGER, di_id TEXT, lesson_id TEXT,
|
|
424
|
+
detail_json TEXT CHECK(detail_json IS NULL OR json_valid(detail_json))) STRICT;
|
|
425
|
+
CREATE INDEX IF NOT EXISTS ix_inv_open ON invariant_violations(cleared_at,code);
|
|
426
|
+
|
|
427
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
428
|
+
-- B3. Máy: dịch vụ, ghế, terminal, giao nhận, lượt, khoá, claim, phiên agent, kiểm kê
|
|
429
|
+
-- Luật chủ sở hữu (không có giao dịch liên DB): tài nguyên máy (terminal, worktree, khoá) do machine làm chủ;
|
|
430
|
+
-- op_attempts chỉ TRỎ tới (terminal_handle, worktree_path). Resource ctrl/GC đối soát lệch hai phía.
|
|
431
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
432
|
+
CREATE TABLE IF NOT EXISTS services(
|
|
433
|
+
name TEXT PRIMARY KEY,
|
|
434
|
+
kind TEXT NOT NULL CHECK(kind IN ('host-app','http','tunnel','connector','scheduled-task','ledger')),
|
|
435
|
+
state TEXT NOT NULL CHECK(state IN ('healthy','ok','degraded','down','quarantined','restarting','booting','stale')),
|
|
436
|
+
since INTEGER, pid INTEGER, port INTEGER, url TEXT,
|
|
437
|
+
last_probe_json TEXT CHECK(last_probe_json IS NULL OR json_valid(last_probe_json)),
|
|
438
|
+
quarantined_until INTEGER) STRICT;
|
|
439
|
+
CREATE TABLE IF NOT EXISTS service_probes(
|
|
440
|
+
probe_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL REFERENCES services(name) ON DELETE CASCADE,
|
|
441
|
+
at INTEGER NOT NULL, ok INTEGER NOT NULL CHECK(ok IN (0,1)), latency_ms INTEGER,
|
|
442
|
+
detail_json TEXT CHECK(detail_json IS NULL OR json_valid(detail_json))) STRICT; -- giữ 14 ngày
|
|
443
|
+
CREATE INDEX IF NOT EXISTS ix_probes ON service_probes(name,at);
|
|
444
|
+
-- service_events (G5): mọi chuyển trạng thái và mọi restart, append-only (thay services.restarts_json bị cửa sổ hoá).
|
|
445
|
+
CREATE TABLE IF NOT EXISTS service_events(
|
|
446
|
+
seq INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL REFERENCES services(name) ON DELETE CASCADE,
|
|
447
|
+
at INTEGER NOT NULL, from_state TEXT, to_state TEXT NOT NULL,
|
|
448
|
+
probe_ms INTEGER, probe_error TEXT,
|
|
449
|
+
action TEXT CHECK(action IS NULL OR action IN ('restart','quarantine','release','none')), action_id TEXT) STRICT;
|
|
450
|
+
CREATE INDEX IF NOT EXISTS ix_service_events ON service_events(name,at);
|
|
451
|
+
CREATE TRIGGER IF NOT EXISTS service_events_append_only BEFORE UPDATE ON service_events BEGIN
|
|
452
|
+
SELECT RAISE(ABORT,'service_events are append-only');
|
|
453
|
+
END;
|
|
454
|
+
|
|
455
|
+
-- seats: ghế LLM sống lâu — MỘT nơi. 'parked' = cố ý không có Kernel (workflow paused/stopped): controller KHÔNG
|
|
456
|
+
-- "sửa" ghế parked (MB-08). Đếm lỗi nhập liên tiếp theo ghế (MB-05) → thay ghế sau K lần trong T phút (SLA SEAT_DEAF).
|
|
457
|
+
CREATE TABLE IF NOT EXISTS seats(
|
|
458
|
+
seat_id TEXT PRIMARY KEY, -- 'kernel:<ledger name>:<wf>' | 'supervisor'
|
|
459
|
+
role TEXT NOT NULL CHECK(role IN ('kernel','supervisor')),
|
|
460
|
+
ledger_id TEXT REFERENCES ledgers(ledger_id), workflow_id TEXT,
|
|
461
|
+
state TEXT NOT NULL CHECK(state IN ('empty','parked','booting','live','busy','stale','dead','replacing','quarantined')),
|
|
462
|
+
parked_reason TEXT,
|
|
463
|
+
terminal_handle TEXT, agent TEXT, model TEXT, routed_by TEXT, pid INTEGER,
|
|
464
|
+
kernel_rev TEXT, acked_rev TEXT,
|
|
465
|
+
booted_at INTEGER, last_seen_at INTEGER, replaced_count INTEGER NOT NULL DEFAULT 0,
|
|
466
|
+
input_failures_consecutive INTEGER NOT NULL DEFAULT 0, -- unwritable/exited/unavailable liên tiếp
|
|
467
|
+
input_failures_total INTEGER NOT NULL DEFAULT 0,
|
|
468
|
+
last_input_failure_at INTEGER, last_input_ok_at INTEGER,
|
|
469
|
+
detail_json TEXT CHECK(detail_json IS NULL OR json_valid(detail_json)),
|
|
470
|
+
CHECK(state<>'parked' OR parked_reason IS NOT NULL)) STRICT;
|
|
471
|
+
|
|
472
|
+
-- deliveries (G11, MB-02): MỌI lần đưa thông điệp tới một ghế (DI, inbox, doorbell, wake, telegram) và kết quả.
|
|
473
|
+
CREATE TABLE IF NOT EXISTS deliveries(
|
|
474
|
+
delivery_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
475
|
+
message_kind TEXT NOT NULL CHECK(message_kind IN ('decision','inbox','doorbell','wake','telegram','notice')),
|
|
476
|
+
message_ref TEXT NOT NULL, -- di_id | inbox_id | msg_id
|
|
477
|
+
ledger_id TEXT, seat_id TEXT REFERENCES seats(seat_id), terminal_handle TEXT,
|
|
478
|
+
channel TEXT NOT NULL,
|
|
479
|
+
attempted_at INTEGER NOT NULL,
|
|
480
|
+
outcome TEXT NOT NULL CHECK(outcome IN ('delivered','busy-deferred','unwritable','exited','unavailable','failed')),
|
|
481
|
+
turn_id INTEGER, -- seat_turns.turn_id mà lời nhắn mở ra
|
|
482
|
+
detail TEXT) STRICT;
|
|
483
|
+
CREATE INDEX IF NOT EXISTS ix_deliveries_seat ON deliveries(seat_id,attempted_at);
|
|
484
|
+
CREATE INDEX IF NOT EXISTS ix_deliveries_msg ON deliveries(message_kind,message_ref);
|
|
485
|
+
-- Đếm lỗi nhập theo ghế nằm trong DB, tự động theo từng giao nhận.
|
|
486
|
+
CREATE TRIGGER IF NOT EXISTS deliveries_count_seat_failures AFTER INSERT ON deliveries WHEN NEW.seat_id IS NOT NULL BEGIN
|
|
487
|
+
UPDATE seats SET
|
|
488
|
+
input_failures_consecutive = CASE WHEN NEW.outcome IN ('unwritable','exited','unavailable','failed')
|
|
489
|
+
THEN input_failures_consecutive+1 ELSE 0 END,
|
|
490
|
+
input_failures_total = input_failures_total + (NEW.outcome IN ('unwritable','exited','unavailable','failed')),
|
|
491
|
+
last_input_failure_at = CASE WHEN NEW.outcome IN ('unwritable','exited','unavailable','failed') THEN NEW.attempted_at ELSE last_input_failure_at END,
|
|
492
|
+
last_input_ok_at = CASE WHEN NEW.outcome='delivered' THEN NEW.attempted_at ELSE last_input_ok_at END
|
|
493
|
+
WHERE seat_id=NEW.seat_id;
|
|
494
|
+
END;
|
|
495
|
+
CREATE TRIGGER IF NOT EXISTS deliveries_append_only BEFORE UPDATE OF outcome, attempted_at, message_ref ON deliveries BEGIN
|
|
496
|
+
SELECT RAISE(ABORT,'deliveries are append-only');
|
|
497
|
+
END;
|
|
498
|
+
|
|
499
|
+
-- seat_turns (G12): mỗi lượt làm việc của ghế: ai đánh thức, kéo dài bao lâu, kết thúc vì sao.
|
|
500
|
+
CREATE TABLE IF NOT EXISTS seat_turns(
|
|
501
|
+
turn_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
502
|
+
seat_id TEXT NOT NULL REFERENCES seats(seat_id),
|
|
503
|
+
woken_by_delivery INTEGER REFERENCES deliveries(delivery_id),
|
|
504
|
+
started_at INTEGER NOT NULL, ended_at INTEGER,
|
|
505
|
+
end_reason TEXT CHECK(end_reason IS NULL OR end_reason IN ('idle','budget','interrupted','replaced','crashed')),
|
|
506
|
+
actions_count INTEGER NOT NULL DEFAULT 0,
|
|
507
|
+
span_id TEXT) STRICT;
|
|
508
|
+
CREATE INDEX IF NOT EXISTS ix_seat_turns ON seat_turns(seat_id,started_at);
|
|
509
|
+
|
|
510
|
+
-- seat_transcript_snapshots (UI-API §2.10): snapshot scrollback định kỳ của ghế Kernel/Supervisor, đã redact.
|
|
511
|
+
CREATE TABLE IF NOT EXISTS seat_transcript_snapshots(
|
|
512
|
+
snapshot_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
513
|
+
seat_id TEXT NOT NULL REFERENCES seats(seat_id),
|
|
514
|
+
terminal_handle TEXT,
|
|
515
|
+
at INTEGER NOT NULL, lines INTEGER NOT NULL, bytes INTEGER NOT NULL,
|
|
516
|
+
sha256 TEXT NOT NULL REFERENCES blobs(sha256),
|
|
517
|
+
UNIQUE(seat_id,sha256)) STRICT;
|
|
518
|
+
CREATE INDEX IF NOT EXISTS ix_seat_snap ON seat_transcript_snapshots(seat_id,at);
|
|
519
|
+
|
|
520
|
+
CREATE TABLE IF NOT EXISTS terminals(
|
|
521
|
+
handle TEXT PRIMARY KEY, title TEXT,
|
|
522
|
+
role TEXT NOT NULL CHECK(role IN ('op','kernel','worker','supervisor','shell','other')),
|
|
523
|
+
ledger_id TEXT, workflow_id TEXT, job_id TEXT, attempt_id INTEGER, sup_attempt_id INTEGER, seat_id TEXT, pid INTEGER,
|
|
524
|
+
owner_ref TEXT, -- MB-13: mọi terminal có chủ hoặc TTL
|
|
525
|
+
expires_at INTEGER,
|
|
526
|
+
opened_at INTEGER, closed_at INTEGER, close_verified_at INTEGER, closed_by TEXT, last_output_at INTEGER,
|
|
527
|
+
refused_count INTEGER NOT NULL DEFAULT 0) STRICT; -- số lần GC từ chối đóng (MB-13: quá N → DI một lần)
|
|
528
|
+
CREATE INDEX IF NOT EXISTS ix_terminals_open ON terminals(closed_at,role);
|
|
529
|
+
CREATE INDEX IF NOT EXISTS ix_terminals_attempt ON terminals(ledger_id,attempt_id);
|
|
530
|
+
|
|
531
|
+
CREATE TABLE IF NOT EXISTS host_locks(
|
|
532
|
+
name TEXT PRIMARY KEY, holder_pid INTEGER NOT NULL, holder TEXT, process_run_id INTEGER REFERENCES process_runs(run_id),
|
|
533
|
+
started_at INTEGER NOT NULL, heartbeat_at INTEGER NOT NULL, expires_at INTEGER NOT NULL,
|
|
534
|
+
handed_over_from INTEGER,
|
|
535
|
+
state TEXT NOT NULL DEFAULT 'held' CHECK(state IN ('starting','held','released'))) STRICT;
|
|
536
|
+
|
|
537
|
+
-- claims (G14, MB-04, MB-17): tài nguyên tạm (thư mục, worktree tạm, file lock) được CLAIM trước khi tạo; GC xoá an toàn
|
|
538
|
+
-- (safeRemoveTree, không đi theo junction) khi pid chủ đã chết.
|
|
539
|
+
CREATE TABLE IF NOT EXISTS claims(
|
|
540
|
+
claim_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
541
|
+
resource_path TEXT NOT NULL,
|
|
542
|
+
kind TEXT NOT NULL CHECK(kind IN ('temp-dir','worktree','lock-file','fixture','scratch')),
|
|
543
|
+
owner_action_id TEXT, owner_pid INTEGER NOT NULL, owner_run_id INTEGER REFERENCES process_runs(run_id),
|
|
544
|
+
has_junctions INTEGER NOT NULL DEFAULT 0 CHECK(has_junctions IN (0,1)),
|
|
545
|
+
created_at INTEGER NOT NULL, released_at INTEGER, swept_at INTEGER, sweep_error TEXT) STRICT;
|
|
546
|
+
CREATE UNIQUE INDEX IF NOT EXISTS ux_claims_live ON claims(resource_path) WHERE released_at IS NULL AND swept_at IS NULL;
|
|
547
|
+
|
|
548
|
+
CREATE TABLE IF NOT EXISTS agent_sessions(
|
|
549
|
+
session_id TEXT PRIMARY KEY,
|
|
550
|
+
agent TEXT NOT NULL CHECK(agent IN ('devin','codex','claude')),
|
|
551
|
+
terminal_handle TEXT, ledger_id TEXT, workflow_id TEXT, job_id TEXT, attempt_id INTEGER, sup_attempt_id INTEGER, seat_id TEXT,
|
|
552
|
+
started_at INTEGER, ended_at INTEGER,
|
|
553
|
+
transcript_sha TEXT REFERENCES blobs(sha256), archive_ref TEXT, bytes INTEGER, archived_at INTEGER) STRICT;
|
|
554
|
+
CREATE INDEX IF NOT EXISTS ix_agent_sessions_attempt ON agent_sessions(ledger_id,attempt_id);
|
|
555
|
+
|
|
556
|
+
-- inventory_snapshots (G15): kiểm kê tiến trình/terminal/worktree/dir tạm mỗi N phút, giữ 7 ngày — thấy rò tăng dần.
|
|
557
|
+
CREATE TABLE IF NOT EXISTS inventory_snapshots(
|
|
558
|
+
snap_at INTEGER NOT NULL,
|
|
559
|
+
kind TEXT NOT NULL CHECK(kind IN ('process','terminal','worktree','temp-dir','lock')),
|
|
560
|
+
key TEXT NOT NULL, -- pid:starttime | handle | path
|
|
561
|
+
owner TEXT, rss_mb INTEGER, age_s INTEGER, detail TEXT,
|
|
562
|
+
PRIMARY KEY(snap_at,kind,key)) STRICT, WITHOUT ROWID;
|
|
563
|
+
|
|
564
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
565
|
+
-- B4. Tài nguyên: RAM/CPU, pool, provider, quota, guard, lease máy, ngân sách
|
|
566
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
567
|
+
CREATE TABLE IF NOT EXISTS throttle_state( -- thay ram-throttle.json (một dòng hiện tại; mang rev người ghi — MB-15)
|
|
568
|
+
id INTEGER PRIMARY KEY CHECK(id=1),
|
|
569
|
+
mode TEXT NOT NULL CHECK(mode IN ('normal','heavy','critical')),
|
|
570
|
+
effective_cap INTEGER, heavy_cap INTEGER, running INTEGER,
|
|
571
|
+
free_ram_pct REAL, free_ram_mb INTEGER, cpu_pct REAL, cpu_hot INTEGER, since INTEGER, updated_at INTEGER NOT NULL,
|
|
572
|
+
reason TEXT, writer TEXT NOT NULL, writer_rev TEXT NOT NULL,
|
|
573
|
+
slot_targets_json TEXT CHECK(slot_targets_json IS NULL OR json_valid(slot_targets_json)),
|
|
574
|
+
priorities_json TEXT CHECK(priorities_json IS NULL OR json_valid(priorities_json))) STRICT;
|
|
575
|
+
-- throttle_events (G7): MỌI chuyển mode, APPEND-ONLY (không ghi đè, không xoá).
|
|
576
|
+
CREATE TABLE IF NOT EXISTS throttle_events(
|
|
577
|
+
seq INTEGER PRIMARY KEY AUTOINCREMENT, at INTEGER NOT NULL,
|
|
578
|
+
from_mode TEXT, to_mode TEXT NOT NULL CHECK(to_mode IN ('normal','heavy','critical')), reason TEXT,
|
|
579
|
+
free_ram_pct REAL, cpu_pct REAL, effective_cap INTEGER, running INTEGER, writer_rev TEXT,
|
|
580
|
+
sample_json TEXT CHECK(sample_json IS NULL OR json_valid(sample_json))) STRICT;
|
|
581
|
+
CREATE TRIGGER IF NOT EXISTS throttle_events_no_update BEFORE UPDATE ON throttle_events BEGIN
|
|
582
|
+
SELECT RAISE(ABORT,'throttle_events are append-only');
|
|
583
|
+
END;
|
|
584
|
+
CREATE TRIGGER IF NOT EXISTS throttle_events_no_delete BEFORE DELETE ON throttle_events BEGIN
|
|
585
|
+
SELECT RAISE(ABORT,'throttle_events are append-only');
|
|
586
|
+
END;
|
|
587
|
+
-- Đổi mode trong throttle_state phải có throttle_events tương ứng ghi trước (không mất chuyển nào).
|
|
588
|
+
CREATE TRIGGER IF NOT EXISTS throttle_state_recorded BEFORE UPDATE OF mode ON throttle_state
|
|
589
|
+
WHEN NEW.mode<>OLD.mode AND NOT EXISTS(SELECT 1 FROM throttle_events e WHERE e.seq=(SELECT max(seq) FROM throttle_events)
|
|
590
|
+
AND e.to_mode=NEW.mode AND e.from_mode IS OLD.mode) BEGIN
|
|
591
|
+
SELECT RAISE(ABORT,'throttle mode change must be recorded in throttle_events first');
|
|
592
|
+
END;
|
|
593
|
+
-- throttle_decisions (G7): op nào bị hoãn vì throttle, bao lâu.
|
|
594
|
+
CREATE TABLE IF NOT EXISTS throttle_decisions(
|
|
595
|
+
seq INTEGER PRIMARY KEY AUTOINCREMENT, at INTEGER NOT NULL, ledger_id TEXT, workflow_id TEXT, job_id TEXT,
|
|
596
|
+
reason TEXT NOT NULL, waited_ms INTEGER, released_at INTEGER) STRICT;
|
|
597
|
+
|
|
598
|
+
CREATE TABLE IF NOT EXISTS host_samples(
|
|
599
|
+
seq INTEGER PRIMARY KEY AUTOINCREMENT, at INTEGER NOT NULL,
|
|
600
|
+
kind TEXT NOT NULL CHECK(kind IN ('host','op-footprint','worker-footprint')),
|
|
601
|
+
ledger_id TEXT, workflow_id TEXT, attempt_id INTEGER, sup_attempt_id INTEGER, subject TEXT,
|
|
602
|
+
ram_mb INTEGER, cpu_pct REAL, free_ram_mb INTEGER, free_ram_pct REAL, free_disk_gb REAL,
|
|
603
|
+
mode TEXT, effective_cap INTEGER, running INTEGER,
|
|
604
|
+
detail_json TEXT CHECK(detail_json IS NULL OR json_valid(detail_json))) STRICT; -- giữ 14 ngày
|
|
605
|
+
CREATE INDEX IF NOT EXISTS ix_host_samples ON host_samples(kind,at);
|
|
606
|
+
CREATE TABLE IF NOT EXISTS provider_health(
|
|
607
|
+
provider TEXT PRIMARY KEY CHECK(provider IN ('devin','codex','claude')),
|
|
608
|
+
status TEXT NOT NULL CHECK(status IN ('healthy','striking','unavailable','recovered')),
|
|
609
|
+
failure_kind TEXT, strikes INTEGER NOT NULL DEFAULT 0, strike_limit INTEGER,
|
|
610
|
+
circuit_open_until INTEGER, recovered_at INTEGER, reason TEXT, updated_at INTEGER NOT NULL,
|
|
611
|
+
detail_json TEXT CHECK(detail_json IS NULL OR json_valid(detail_json))) STRICT;
|
|
612
|
+
CREATE TABLE IF NOT EXISTS provider_health_events(
|
|
613
|
+
seq INTEGER PRIMARY KEY AUTOINCREMENT, provider TEXT NOT NULL, at INTEGER NOT NULL, from_status TEXT, to_status TEXT,
|
|
614
|
+
failure_kind TEXT, ledger_id TEXT, attempt_id INTEGER,
|
|
615
|
+
detail_json TEXT CHECK(detail_json IS NULL OR json_valid(detail_json))) STRICT;
|
|
616
|
+
CREATE TABLE IF NOT EXISTS pool_backoff(
|
|
617
|
+
pool TEXT PRIMARY KEY, until_at INTEGER, strikes INTEGER NOT NULL DEFAULT 0, reason TEXT, updated_at INTEGER NOT NULL) STRICT;
|
|
618
|
+
CREATE TABLE IF NOT EXISTS quotas(
|
|
619
|
+
provider TEXT NOT NULL, window TEXT NOT NULL, used REAL, limit_value REAL, reset_at INTEGER, source TEXT,
|
|
620
|
+
observed_at INTEGER NOT NULL, PRIMARY KEY(provider,window)) STRICT;
|
|
621
|
+
CREATE TABLE IF NOT EXISTS guard_jobs( -- thay .claude/runtime/guards/jobs/<job>.json (STARCI_GUARD_FILE)
|
|
622
|
+
job_id TEXT PRIMARY KEY, ledger_id TEXT, workflow_id TEXT, attempt_id INTEGER,
|
|
623
|
+
allow_json TEXT NOT NULL CHECK(json_valid(allow_json)),
|
|
624
|
+
hooks_json TEXT CHECK(hooks_json IS NULL OR json_valid(hooks_json)),
|
|
625
|
+
created_at INTEGER NOT NULL, expires_at INTEGER NOT NULL, released_at INTEGER) STRICT;
|
|
626
|
+
CREATE TABLE IF NOT EXISTS guard_refusals( -- thay .claude/runtime/guards/refusals.jsonl
|
|
627
|
+
seq INTEGER PRIMARY KEY AUTOINCREMENT, at INTEGER NOT NULL, ledger_id TEXT, workflow_id TEXT, job_id TEXT, attempt_id INTEGER,
|
|
628
|
+
tool TEXT, command TEXT, code TEXT, reason TEXT, remedy TEXT, cwd TEXT) STRICT;
|
|
629
|
+
CREATE TABLE IF NOT EXISTS host_resources(resource_key TEXT PRIMARY KEY, capacity INTEGER NOT NULL CHECK(capacity>=0)) STRICT;
|
|
630
|
+
CREATE TABLE IF NOT EXISTS host_leases(
|
|
631
|
+
resource_key TEXT NOT NULL, token TEXT NOT NULL, ledger_id TEXT NOT NULL REFERENCES ledgers(ledger_id),
|
|
632
|
+
workflow_id TEXT NOT NULL, job_id TEXT NOT NULL, attempt_id INTEGER, holder TEXT, units INTEGER NOT NULL CHECK(units>0),
|
|
633
|
+
acquired_at INTEGER NOT NULL, expires_at INTEGER NOT NULL CHECK(expires_at>acquired_at), PRIMARY KEY(resource_key,token)) STRICT;
|
|
634
|
+
CREATE INDEX IF NOT EXISTS ix_host_leases_expiry ON host_leases(expires_at);
|
|
635
|
+
CREATE TABLE IF NOT EXISTS budgets(
|
|
636
|
+
scope_key TEXT PRIMARY KEY, limit_value INTEGER NOT NULL, used_value INTEGER NOT NULL DEFAULT 0,
|
|
637
|
+
reserved_value INTEGER NOT NULL DEFAULT 0, window TEXT, updated_at INTEGER) STRICT;
|
|
638
|
+
CREATE TABLE IF NOT EXISTS budget_reservations(
|
|
639
|
+
scope_key TEXT NOT NULL REFERENCES budgets(scope_key), ledger_id TEXT NOT NULL, job_id TEXT NOT NULL,
|
|
640
|
+
units INTEGER NOT NULL, at INTEGER, PRIMARY KEY(scope_key,ledger_id,job_id)) STRICT;
|
|
641
|
+
|
|
642
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
643
|
+
-- B5. GC, land gate, push, lane, worktree, môi trường
|
|
644
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
645
|
+
CREATE TABLE IF NOT EXISTS gc_runs(
|
|
646
|
+
run_id INTEGER PRIMARY KEY AUTOINCREMENT, action_id TEXT, started_at INTEGER NOT NULL, finished_at INTEGER,
|
|
647
|
+
trigger TEXT CHECK(trigger IS NULL OR trigger IN ('event','sweep','housekeeping','low-disk','low-ram','blob-sweep','manual')),
|
|
648
|
+
freed_bytes INTEGER,
|
|
649
|
+
collectors_json TEXT CHECK(collectors_json IS NULL OR json_valid(collectors_json)),
|
|
650
|
+
counts_json TEXT CHECK(counts_json IS NULL OR json_valid(counts_json)),
|
|
651
|
+
errors_json TEXT CHECK(errors_json IS NULL OR json_valid(errors_json)),
|
|
652
|
+
report_sha TEXT REFERENCES blobs(sha256)) STRICT; -- báo cáo đầy đủ (G4: không cắt)
|
|
653
|
+
-- gc_items (G4, MB-14): MỖI thứ GC chạm tới một dòng: thu/từ chối/giữ, bao nhiêu byte, thử lại mấy lần, kết cục CUỐI.
|
|
654
|
+
CREATE TABLE IF NOT EXISTS gc_items(
|
|
655
|
+
item_id INTEGER PRIMARY KEY AUTOINCREMENT, run_id INTEGER REFERENCES gc_runs(run_id) ON DELETE CASCADE,
|
|
656
|
+
collector TEXT NOT NULL, kind TEXT NOT NULL, target TEXT NOT NULL, owner_ref TEXT, age_ms INTEGER,
|
|
657
|
+
action TEXT NOT NULL CHECK(action IN ('collect','refuse','keep','closed','killed','removed','archived','failed')),
|
|
658
|
+
reason TEXT, bytes INTEGER,
|
|
659
|
+
tries INTEGER NOT NULL DEFAULT 1, next_try_at INTEGER, -- retry đặt vào grace - age + margin, không đúng bằng grace
|
|
660
|
+
last_error TEXT,
|
|
661
|
+
outcome TEXT CHECK(outcome IS NULL OR outcome IN ('done','dropped','gave-up')), -- kết cục cuối, luôn được ghi
|
|
662
|
+
verified_gone_at INTEGER,
|
|
663
|
+
at INTEGER NOT NULL) STRICT;
|
|
664
|
+
CREATE INDEX IF NOT EXISTS ix_gc_items_kind ON gc_items(collector,kind,at);
|
|
665
|
+
CREATE INDEX IF NOT EXISTS ix_gc_items_open ON gc_items(outcome,next_try_at);
|
|
666
|
+
CREATE TABLE IF NOT EXISTS gc_marks(
|
|
667
|
+
run_id INTEGER NOT NULL REFERENCES gc_runs(run_id) ON DELETE CASCADE,
|
|
668
|
+
sha256 TEXT NOT NULL,
|
|
669
|
+
source TEXT NOT NULL, -- ledger name | 'machine'
|
|
670
|
+
pinned INTEGER NOT NULL DEFAULT 0 CHECK(pinned IN (0,1)),
|
|
671
|
+
PRIMARY KEY(run_id,sha256,source)) STRICT, WITHOUT ROWID;
|
|
672
|
+
|
|
673
|
+
CREATE TABLE IF NOT EXISTS lanes(
|
|
674
|
+
name TEXT PRIMARY KEY, worktree_path TEXT NOT NULL, branch TEXT NOT NULL, base_sha TEXT, head_sha TEXT,
|
|
675
|
+
owner TEXT NOT NULL, -- 'supervisor' | 'owner-chat' | 'worker:<job>'
|
|
676
|
+
sup_job_id TEXT REFERENCES sup_jobs(job_id),
|
|
677
|
+
state TEXT NOT NULL CHECK(state IN ('open','landing','landed','abandoned','removed')),
|
|
678
|
+
created_at INTEGER NOT NULL, landed_at INTEGER, removed_at INTEGER,
|
|
679
|
+
report_sha TEXT REFERENCES blobs(sha256)) STRICT;
|
|
680
|
+
-- land_queue (G9, MB-10): thời điểm vào gate và ai giữ gate khi bận.
|
|
681
|
+
CREATE TABLE IF NOT EXISTS land_queue(
|
|
682
|
+
ticket_id TEXT PRIMARY KEY, lane TEXT REFERENCES lanes(name), commit_sha TEXT NOT NULL, commits INTEGER, requested_by TEXT,
|
|
683
|
+
state TEXT NOT NULL CHECK(state IN ('queued','running','passed','failed','cancelled')),
|
|
684
|
+
enqueued_at INTEGER NOT NULL, gate_at INTEGER, busy_holder TEXT, started_at INTEGER, finished_at INTEGER) STRICT;
|
|
685
|
+
CREATE INDEX IF NOT EXISTS ix_land_queue_state ON land_queue(state,enqueued_at);
|
|
686
|
+
CREATE TABLE IF NOT EXISTS land_runs(
|
|
687
|
+
run_id INTEGER PRIMARY KEY AUTOINCREMENT, ticket_id TEXT REFERENCES land_queue(ticket_id), lane TEXT,
|
|
688
|
+
span_id TEXT NOT NULL CHECK(length(span_id)=16), parent_span_id TEXT,
|
|
689
|
+
commit_sha TEXT NOT NULL, landed_sha TEXT,
|
|
690
|
+
commits_json TEXT CHECK(commits_json IS NULL OR (json_valid(commits_json) AND json_type(commits_json)='array')), -- every picked commit, in order (a3-2)
|
|
691
|
+
result TEXT NOT NULL CHECK(result IN ('passed','failed','conflict','refused')), reason TEXT,
|
|
692
|
+
push_id INTEGER, -- MB-12: land 'passed' nối với kết quả push thật
|
|
693
|
+
specs_json TEXT CHECK(specs_json IS NULL OR json_valid(specs_json)),
|
|
694
|
+
stdout_sha TEXT REFERENCES blobs(sha256), stderr_sha TEXT REFERENCES blobs(sha256),
|
|
695
|
+
started_at INTEGER NOT NULL, finished_at INTEGER) STRICT;
|
|
696
|
+
CREATE INDEX IF NOT EXISTS ix_land_runs_lane ON land_runs(lane,started_at);
|
|
697
|
+
-- pushes (G8, MB-03): mỗi lần push một dòng, có chữ ký lỗi ổn định và log ĐẦY ĐỦ ở blob.
|
|
698
|
+
CREATE TABLE IF NOT EXISTS pushes(
|
|
699
|
+
push_id INTEGER PRIMARY KEY AUTOINCREMENT, repo_root TEXT NOT NULL, branch TEXT, head TEXT NOT NULL, from_sha TEXT, to_sha TEXT,
|
|
700
|
+
result TEXT NOT NULL CHECK(result IN ('pushed','refused','skipped','failed')), reason TEXT,
|
|
701
|
+
failure_signature TEXT, -- secret-scan:<rule> | lint:<rule> | jest:<suite> ... (không chứa HEAD)
|
|
702
|
+
ms INTEGER, action_id TEXT,
|
|
703
|
+
scan_json TEXT CHECK(scan_json IS NULL OR json_valid(scan_json)),
|
|
704
|
+
stdout_sha TEXT REFERENCES blobs(sha256), stderr_sha TEXT REFERENCES blobs(sha256),
|
|
705
|
+
at INTEGER NOT NULL,
|
|
706
|
+
CHECK(result IN ('pushed','skipped') OR failure_signature IS NOT NULL)) STRICT;
|
|
707
|
+
CREATE INDEX IF NOT EXISTS ix_pushes ON pushes(repo_root,at);
|
|
708
|
+
|
|
709
|
+
CREATE TABLE IF NOT EXISTS worktrees(
|
|
710
|
+
path TEXT PRIMARY KEY,
|
|
711
|
+
kind TEXT NOT NULL CHECK(kind IN ('op','workflow','land-scratch','push-scratch','supervisor-staging','lane')),
|
|
712
|
+
repo_root TEXT NOT NULL, branch TEXT, base_sha TEXT, head_sha TEXT, port INTEGER,
|
|
713
|
+
ledger_id TEXT, workflow_id TEXT, job_id TEXT, attempt_id INTEGER, lane TEXT, claim_id INTEGER REFERENCES claims(claim_id),
|
|
714
|
+
created_at INTEGER NOT NULL, removed_at INTEGER, archived_ref TEXT, remove_error TEXT) STRICT;
|
|
715
|
+
CREATE INDEX IF NOT EXISTS ix_worktrees_live ON worktrees(removed_at,kind);
|
|
716
|
+
CREATE INDEX IF NOT EXISTS ix_worktrees_attempt ON worktrees(ledger_id,attempt_id);
|
|
717
|
+
|
|
718
|
+
CREATE TABLE IF NOT EXISTS env_servers(
|
|
719
|
+
server_id TEXT PRIMARY KEY, env TEXT, service TEXT, repo_root TEXT,
|
|
720
|
+
ledger_id TEXT, workflow_id TEXT, job_id TEXT, attempt_id INTEGER,
|
|
721
|
+
command TEXT, cwd TEXT, port INTEGER, pid INTEGER, url TEXT,
|
|
722
|
+
state TEXT NOT NULL CHECK(state IN ('starting','ready','failed','stopped')),
|
|
723
|
+
started_at INTEGER, stopped_at INTEGER, log_sha TEXT REFERENCES blobs(sha256)) STRICT;
|
|
724
|
+
CREATE TABLE IF NOT EXISTS uat_slots(
|
|
725
|
+
slot_id TEXT PRIMARY KEY, ledger_id TEXT, workflow_id TEXT, job_id TEXT, attempt_id INTEGER,
|
|
726
|
+
browser_profile TEXT, port INTEGER, acquired_at INTEGER, expires_at INTEGER, released_at INTEGER) STRICT;
|
|
727
|
+
CREATE TABLE IF NOT EXISTS connectors( -- KHÔNG chứa bí mật; bí mật ở .starcistacks + sops
|
|
728
|
+
name TEXT PRIMARY KEY, kind TEXT, state TEXT, pid INTEGER, port INTEGER, public_url TEXT,
|
|
729
|
+
config_json TEXT CHECK(config_json IS NULL OR json_valid(config_json)),
|
|
730
|
+
cursor_json TEXT CHECK(cursor_json IS NULL OR json_valid(cursor_json)), -- vd telegram offset, route chats
|
|
731
|
+
updated_at INTEGER NOT NULL) STRICT;
|
|
732
|
+
CREATE TABLE IF NOT EXISTS ask_requests(
|
|
733
|
+
ask_id TEXT PRIMARY KEY, ledger_id TEXT, workflow_id TEXT, di_id TEXT, channel TEXT, question TEXT NOT NULL,
|
|
734
|
+
form_url TEXT,
|
|
735
|
+
state TEXT NOT NULL CHECK(state IN ('open','answered','retired','expired')),
|
|
736
|
+
asked_at INTEGER NOT NULL, answered_at INTEGER, answer_ref TEXT) STRICT;
|
|
737
|
+
|
|
738
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
739
|
+
-- B6. Quan sát cấp máy
|
|
740
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
741
|
+
CREATE TABLE IF NOT EXISTS machine_logs(
|
|
742
|
+
seq INTEGER PRIMARY KEY AUTOINCREMENT, at INTEGER NOT NULL,
|
|
743
|
+
actor TEXT NOT NULL CHECK(actor IN ('reconciler','supervisor','worker','gc','host','land','watchdog','connector','harness','runtime')),
|
|
744
|
+
controller TEXT, ledger_id TEXT, workflow_id TEXT, job_id TEXT, attempt_id INTEGER, action_id TEXT,
|
|
745
|
+
trace_id TEXT, span_id TEXT,
|
|
746
|
+
level TEXT NOT NULL CHECK(level IN ('debug','info','warn','error')),
|
|
747
|
+
kind TEXT NOT NULL, msg TEXT NOT NULL,
|
|
748
|
+
data_json TEXT CHECK(data_json IS NULL OR json_valid(data_json)),
|
|
749
|
+
refs_json TEXT CHECK(refs_json IS NULL OR json_valid(refs_json)),
|
|
750
|
+
src TEXT UNIQUE) STRICT; -- append-only; GC xoá theo retention (debug 14 ngày, còn lại 90 ngày)
|
|
751
|
+
CREATE INDEX IF NOT EXISTS ix_mlogs_at ON machine_logs(at);
|
|
752
|
+
CREATE INDEX IF NOT EXISTS ix_mlogs_kind ON machine_logs(actor,kind,seq);
|
|
753
|
+
CREATE INDEX IF NOT EXISTS ix_mlogs_ent ON machine_logs(ledger_id,workflow_id,job_id,seq);
|
|
754
|
+
CREATE TRIGGER IF NOT EXISTS machine_logs_append_only BEFORE UPDATE ON machine_logs BEGIN
|
|
755
|
+
SELECT RAISE(ABORT,'machine_logs are append-only');
|
|
756
|
+
END;
|
|
757
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS machine_logs_fts USING fts5(msg, kind, controller, content='machine_logs', content_rowid='seq',
|
|
758
|
+
tokenize='unicode61 remove_diacritics 2');
|
|
759
|
+
CREATE TRIGGER IF NOT EXISTS machine_logs_fts_insert AFTER INSERT ON machine_logs BEGIN
|
|
760
|
+
INSERT INTO machine_logs_fts(rowid,msg,kind,controller) VALUES (NEW.seq,NEW.msg,NEW.kind,NEW.controller);
|
|
761
|
+
END;
|
|
762
|
+
CREATE TRIGGER IF NOT EXISTS machine_logs_fts_delete AFTER DELETE ON machine_logs BEGIN
|
|
763
|
+
INSERT INTO machine_logs_fts(machine_logs_fts,rowid,msg,kind,controller) VALUES ('delete',OLD.seq,OLD.msg,OLD.kind,OLD.controller);
|
|
764
|
+
END;
|
|
765
|
+
|
|
766
|
+
-- metrics_snapshots: controller ghi (progress, rca, frontier, coverage, verify ...) để harness KHÔNG phải chạy verb.
|
|
767
|
+
CREATE TABLE IF NOT EXISTS metrics_snapshots(
|
|
768
|
+
snap_id INTEGER PRIMARY KEY AUTOINCREMENT, at INTEGER NOT NULL,
|
|
769
|
+
kind TEXT NOT NULL CHECK(kind IN ('op-health','progress','rca','frontier','coverage','verify','model-scorecard','throughput','ram')),
|
|
770
|
+
ledger_id TEXT, workflow_id TEXT, window_ms INTEGER, subject TEXT,
|
|
771
|
+
data_json TEXT CHECK(data_json IS NULL OR json_valid(data_json)),
|
|
772
|
+
data_sha TEXT REFERENCES blobs(sha256)) STRICT;
|
|
773
|
+
CREATE INDEX IF NOT EXISTS ix_metrics ON metrics_snapshots(kind,ledger_id,workflow_id,at);
|
|
774
|
+
|
|
775
|
+
CREATE TABLE IF NOT EXISTS notifications(
|
|
776
|
+
notif_id INTEGER PRIMARY KEY AUTOINCREMENT, channel TEXT NOT NULL,
|
|
777
|
+
kind TEXT NOT NULL CHECK(kind IN ('digest','urgent','ask','ack','media')),
|
|
778
|
+
text TEXT NOT NULL, media_sha TEXT REFERENCES blobs(sha256), sent_at INTEGER, delivery TEXT, ref TEXT,
|
|
779
|
+
dedupe_key TEXT UNIQUE) STRICT; -- thay telegram-sent.json / telegram-media-sent.json
|
|
780
|
+
|
|
781
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
782
|
+
-- B7. View bền của machine.sqlite
|
|
783
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
784
|
+
CREATE VIEW IF NOT EXISTS v_services AS
|
|
785
|
+
SELECT s.*, COALESCE(m.ui,'unknown') AS ui,
|
|
786
|
+
(SELECT count(*) FROM service_events e WHERE e.name=s.name AND e.action='restart'
|
|
787
|
+
AND e.at > CAST(unixepoch('subsec')*1000 AS INTEGER) - 86400000) AS restarts_24h,
|
|
788
|
+
(SELECT count(*) FROM service_probes p WHERE p.name=s.name AND p.ok=0
|
|
789
|
+
AND p.at > CAST(unixepoch('subsec')*1000 AS INTEGER) - 86400000) AS failed_probes_24h
|
|
790
|
+
FROM services s LEFT JOIN ui_state_map m ON m.entity='service' AND m.native=s.state;
|
|
791
|
+
|
|
792
|
+
CREATE VIEW IF NOT EXISTS v_seats AS
|
|
793
|
+
SELECT s.*, COALESCE(m.ui,'unknown') AS ui, t.closed_at AS terminal_closed_at, t.last_output_at,
|
|
794
|
+
(SELECT max(at) FROM seat_transcript_snapshots x WHERE x.seat_id=s.seat_id) AS last_snapshot_at
|
|
795
|
+
FROM seats s LEFT JOIN ui_state_map m ON m.entity='seat' AND m.native=s.state
|
|
796
|
+
LEFT JOIN terminals t ON t.handle=s.terminal_handle;
|
|
797
|
+
|
|
798
|
+
CREATE VIEW IF NOT EXISTS v_engine_actions AS
|
|
799
|
+
SELECT a.*, COALESCE(m.ui,'unknown') AS ui FROM engine_actions a
|
|
800
|
+
LEFT JOIN ui_state_map m ON m.entity='engine-action' AND m.native=a.state;
|
|
801
|
+
|
|
802
|
+
-- Đồng hồ SLA đang mở (thay bảng sla_clocks cũ).
|
|
803
|
+
CREATE VIEW IF NOT EXISTS v_sla_open AS
|
|
804
|
+
SELECT e.*, e.entered_at + e.sla_ms AS due_at,
|
|
805
|
+
CASE WHEN e.violated_at IS NULL THEN 'waiting' WHEN e.severity='critical' THEN 'bad' ELSE 'warn' END AS ui
|
|
806
|
+
FROM sla_episodes e WHERE e.cleared_at IS NULL;
|
|
807
|
+
|
|
808
|
+
-- Nhiệm vụ định kỳ quá hạn hoặc chạy quá dày (MB-01).
|
|
809
|
+
CREATE VIEW IF NOT EXISTS v_schedules AS
|
|
810
|
+
SELECT s.*, (CAST(unixepoch('subsec')*1000 AS INTEGER) - s.next_due_at) AS overdue_ms,
|
|
811
|
+
(SELECT count(*) FROM engine_actions a WHERE a.controller=s.controller AND a.duty=s.duty
|
|
812
|
+
AND a.started_at > CAST(unixepoch('subsec')*1000 AS INTEGER) - 86400000) AS runs_24h,
|
|
813
|
+
CASE WHEN (SELECT count(*) FROM engine_actions a WHERE a.controller=s.controller AND a.duty=s.duty
|
|
814
|
+
AND a.started_at > CAST(unixepoch('subsec')*1000 AS INTEGER) - 86400000) > 2 * (86400000 / s.interval_ms) + 1 THEN 'bad'
|
|
815
|
+
WHEN s.next_due_at < CAST(unixepoch('subsec')*1000 AS INTEGER) - s.interval_ms THEN 'warn' ELSE 'ok' END AS ui
|
|
816
|
+
FROM schedules s;
|
|
817
|
+
|
|
818
|
+
CREATE VIEW IF NOT EXISTS v_open_sup_decisions AS
|
|
819
|
+
SELECT di_id, kind, summary, status, opened_at, due_at, escalations, delivered_at,
|
|
820
|
+
(CAST(unixepoch('subsec')*1000 AS INTEGER) - opened_at) AS age_ms,
|
|
821
|
+
CASE WHEN due_at IS NOT NULL AND due_at < CAST(unixepoch('subsec')*1000 AS INTEGER) THEN 'bad'
|
|
822
|
+
WHEN delivered_at IS NULL THEN 'warn'
|
|
823
|
+
WHEN status='claimed' THEN 'running' ELSE 'waiting' END AS ui
|
|
824
|
+
FROM sup_decision_items WHERE status IN ('open','claimed','escalated');
|
|
825
|
+
|
|
826
|
+
-- Ghế điếc (MB-05): lỗi nhập liên tiếp ≥ 3 → SLA SEAT_DEAF → thay ghế.
|
|
827
|
+
CREATE VIEW IF NOT EXISTS v_deaf_seats AS
|
|
828
|
+
SELECT seat_id, role, workflow_id, state, input_failures_consecutive, last_input_failure_at, last_input_ok_at
|
|
829
|
+
FROM seats WHERE state NOT IN ('parked','empty') AND input_failures_consecutive >= 3;
|
|
830
|
+
|
|
831
|
+
CREATE VIEW IF NOT EXISTS v_leaks AS
|
|
832
|
+
SELECT 'worktree' AS kind, path AS target, ledger_id, job_id AS owner, created_at AS since FROM worktrees
|
|
833
|
+
WHERE removed_at IS NULL AND kind IN ('op','push-scratch','land-scratch')
|
|
834
|
+
UNION ALL SELECT 'terminal', handle, ledger_id, COALESCE(owner_ref,job_id), opened_at FROM terminals
|
|
835
|
+
WHERE closed_at IS NULL AND (role IN ('op','worker') OR (owner_ref IS NULL AND expires_at < CAST(unixepoch('subsec')*1000 AS INTEGER)))
|
|
836
|
+
UNION ALL SELECT 'lease', resource_key, ledger_id, job_id, acquired_at FROM host_leases
|
|
837
|
+
WHERE expires_at < CAST(unixepoch('subsec')*1000 AS INTEGER)
|
|
838
|
+
UNION ALL SELECT 'lease', path, NULL, job_id, acquired_at FROM sup_leases WHERE expires_at < CAST(unixepoch('subsec')*1000 AS INTEGER)
|
|
839
|
+
UNION ALL SELECT 'guard', job_id, ledger_id, job_id, created_at FROM guard_jobs
|
|
840
|
+
WHERE released_at IS NULL AND expires_at < CAST(unixepoch('subsec')*1000 AS INTEGER)
|
|
841
|
+
UNION ALL SELECT 'claim', resource_path, NULL, owner_action_id, created_at FROM claims
|
|
842
|
+
WHERE released_at IS NULL AND swept_at IS NULL AND created_at < CAST(unixepoch('subsec')*1000 AS INTEGER) - 3600000
|
|
843
|
+
UNION ALL SELECT 'lock', name, NULL, holder, started_at FROM host_locks
|
|
844
|
+
WHERE state<>'released' AND expires_at < CAST(unixepoch('subsec')*1000 AS INTEGER);
|
|
845
|
+
|
|
846
|
+
CREATE VIEW IF NOT EXISTS v_engine_health AS
|
|
847
|
+
SELECT l.holder, l.pid, l.epoch, l.rev, l.heartbeat_at, l.draining, l.passes, l.last_pass_ms, l.last_error,
|
|
848
|
+
(CAST(unixepoch('subsec')*1000 AS INTEGER) - l.heartbeat_at) AS heartbeat_age_ms,
|
|
849
|
+
(SELECT count(*) FROM process_runs r WHERE r.role='engine' AND r.started_at > CAST(unixepoch('subsec')*1000 AS INTEGER) - 3600000) AS starts_last_hour,
|
|
850
|
+
(SELECT count(*) FROM process_runs r WHERE r.role='engine' AND r.exit_reason IN ('crash','killed','lost-lease')
|
|
851
|
+
AND r.ended_at > CAST(unixepoch('subsec')*1000 AS INTEGER) - 86400000) AS bad_exits_24h,
|
|
852
|
+
(SELECT count(*) FROM engine_queue) AS queue_depth,
|
|
853
|
+
(SELECT count(*) FROM sla_episodes WHERE violated_at IS NOT NULL AND cleared_at IS NULL) AS open_violations,
|
|
854
|
+
CASE WHEN l.expires_at < CAST(unixepoch('subsec')*1000 AS INTEGER) THEN 'bad'
|
|
855
|
+
WHEN l.last_error IS NOT NULL OR l.draining=1 THEN 'warn' ELSE 'ok' END AS ui
|
|
856
|
+
FROM engine_leader l;
|
|
857
|
+
|
|
858
|
+
CREATE VIEW IF NOT EXISTS v_search_ids AS
|
|
859
|
+
SELECT 'sup-decision' AS kind, di_id AS id, summary AS title FROM sup_decision_items
|
|
860
|
+
UNION ALL SELECT 'sup-job', job_id, title FROM sup_jobs
|
|
861
|
+
UNION ALL SELECT 'trace', trace_id, title FROM sup_jobs
|
|
862
|
+
UNION ALL SELECT 'lane', name, branch FROM lanes
|
|
863
|
+
UNION ALL SELECT 'land-ticket', ticket_id, commit_sha FROM land_queue
|
|
864
|
+
UNION ALL SELECT 'commit', landed_sha, lane FROM land_runs WHERE landed_sha IS NOT NULL
|
|
865
|
+
UNION ALL SELECT 'action', id, controller||' '||COALESCE(verb,'') FROM engine_actions
|
|
866
|
+
UNION ALL SELECT 'terminal', handle, title FROM terminals
|
|
867
|
+
UNION ALL SELECT 'seat', seat_id, state FROM seats
|
|
868
|
+
UNION ALL SELECT 'service', name, state FROM services
|
|
869
|
+
UNION ALL SELECT 'worktree', path, branch FROM worktrees
|
|
870
|
+
UNION ALL SELECT 'ledger', name, repo_root FROM ledgers
|
|
871
|
+
UNION ALL SELECT 'blob', sha256, media_type FROM blobs;
|
|
872
|
+
|
|
873
|
+
CREATE VIEW IF NOT EXISTS v_live_marks AS
|
|
874
|
+
SELECT 'machine_logs' AS topic, COALESCE(max(seq),0) AS mark FROM machine_logs
|
|
875
|
+
UNION ALL SELECT 'engine_actions', COALESCE(max(COALESCE(finished_at,started_at)),0) FROM engine_actions
|
|
876
|
+
UNION ALL SELECT 'violations', COALESCE(max(max(violation_id), max(COALESCE(cleared_at,0))),0) FROM invariant_violations
|
|
877
|
+
UNION ALL SELECT 'services', COALESCE(max(seq),0) FROM service_events
|
|
878
|
+
UNION ALL SELECT 'deliveries', COALESCE(max(delivery_id),0) FROM deliveries
|
|
879
|
+
UNION ALL SELECT 'sup_decisions', COALESCE(max(max(opened_at), max(COALESCE(resolved_at,0))),0) FROM sup_decision_items;
|
|
880
|
+
|
|
881
|
+
-- ---------------------------------------------------------------------------------------------------------
|
|
882
|
+
-- B8. Truy vấn liên DB — KHÔNG có view bền (SQLite cấm view của main tham chiếu DB ATTACH).
|
|
883
|
+
-- * Danh sách fleet (progress, op_history, media, open_work, blocking, settle_overdue, scorecard): engine/machine-db.mjs
|
|
884
|
+
-- forEachLedger(fn) mở từng runtime.sqlite read-only, chạy view cùng tên, gắn cột ledger, gộp trong JS.
|
|
885
|
+
-- attachFleet(batch ≤ 9) chỉ cho truy vấn tay.
|
|
886
|
+
-- * Blob GC: mark theo TỪNG ledger vào gc_marks (theo blob_ref_columns của mỗi DB) rồi sweep — không ATTACH-UNION.
|
|
887
|
+
-- ---------------------------------------------------------------------------------------------------------
|