@juzser/blacksmith 0.1.0
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/.claude/agents/auditor.md +146 -0
- package/.claude/agents/coder.md +164 -0
- package/.claude/agents/grader.md +110 -0
- package/.claude/agents/merger.md +107 -0
- package/.claude/agents/planner.md +92 -0
- package/.claude/agents/researcher.md +105 -0
- package/.claude/agents/reviewer.md +171 -0
- package/.claude/agents/scribe.md +72 -0
- package/.claude/agents/security-reviewer.md +130 -0
- package/.claude/agents/spec-reviewer.md +215 -0
- package/.claude/agents/tester.md +121 -0
- package/.claude/agents/uiux.md +126 -0
- package/.claude/agents/verifier.md +103 -0
- package/.claude/agents/wave-runner.md +74 -0
- package/LICENSE +21 -0
- package/README.md +389 -0
- package/factory/orchestrator/dist/actors.js +46 -0
- package/factory/orchestrator/dist/agents-registry.js +308 -0
- package/factory/orchestrator/dist/args.js +84 -0
- package/factory/orchestrator/dist/artifacts.js +111 -0
- package/factory/orchestrator/dist/attribution.js +160 -0
- package/factory/orchestrator/dist/audit.js +812 -0
- package/factory/orchestrator/dist/autonomy.js +151 -0
- package/factory/orchestrator/dist/budgetAlarm.js +366 -0
- package/factory/orchestrator/dist/budgets.js +196 -0
- package/factory/orchestrator/dist/claims.js +633 -0
- package/factory/orchestrator/dist/cli.js +3185 -0
- package/factory/orchestrator/dist/commit.js +152 -0
- package/factory/orchestrator/dist/coverage.js +188 -0
- package/factory/orchestrator/dist/crossFinding.js +479 -0
- package/factory/orchestrator/dist/crosscheck.js +396 -0
- package/factory/orchestrator/dist/daemon.js +707 -0
- package/factory/orchestrator/dist/db/projector.js +1317 -0
- package/factory/orchestrator/dist/db/queries.js +1714 -0
- package/factory/orchestrator/dist/db/schema.js +305 -0
- package/factory/orchestrator/dist/delegation.js +400 -0
- package/factory/orchestrator/dist/diffstat.js +164 -0
- package/factory/orchestrator/dist/dispatchAudit.js +275 -0
- package/factory/orchestrator/dist/dotenv.js +72 -0
- package/factory/orchestrator/dist/effort.js +202 -0
- package/factory/orchestrator/dist/epic.js +1018 -0
- package/factory/orchestrator/dist/epicWidth.js +238 -0
- package/factory/orchestrator/dist/errorIssues.js +249 -0
- package/factory/orchestrator/dist/errors.js +11 -0
- package/factory/orchestrator/dist/escalation.js +500 -0
- package/factory/orchestrator/dist/events.js +1015 -0
- package/factory/orchestrator/dist/findingAge.js +91 -0
- package/factory/orchestrator/dist/findingContext.js +103 -0
- package/factory/orchestrator/dist/findings.js +1156 -0
- package/factory/orchestrator/dist/gate.js +911 -0
- package/factory/orchestrator/dist/gh.js +146 -0
- package/factory/orchestrator/dist/git.js +87 -0
- package/factory/orchestrator/dist/goalCheck.js +380 -0
- package/factory/orchestrator/dist/graph.js +61 -0
- package/factory/orchestrator/dist/hookDecision.js +106 -0
- package/factory/orchestrator/dist/immutability.js +171 -0
- package/factory/orchestrator/dist/impact.js +280 -0
- package/factory/orchestrator/dist/integration.js +141 -0
- package/factory/orchestrator/dist/judgePreflight.js +155 -0
- package/factory/orchestrator/dist/judges.js +310 -0
- package/factory/orchestrator/dist/lessonAudit.js +399 -0
- package/factory/orchestrator/dist/lessons.js +1329 -0
- package/factory/orchestrator/dist/mcp.js +555 -0
- package/factory/orchestrator/dist/paths.js +82 -0
- package/factory/orchestrator/dist/plan.js +502 -0
- package/factory/orchestrator/dist/planQuorum.js +421 -0
- package/factory/orchestrator/dist/policy.js +1308 -0
- package/factory/orchestrator/dist/policyHook.js +28 -0
- package/factory/orchestrator/dist/preconditions.js +47 -0
- package/factory/orchestrator/dist/projects.js +134 -0
- package/factory/orchestrator/dist/prompts.js +57 -0
- package/factory/orchestrator/dist/provenance.js +201 -0
- package/factory/orchestrator/dist/providers/api-transport.js +117 -0
- package/factory/orchestrator/dist/providers/cli-transport.js +208 -0
- package/factory/orchestrator/dist/providers/index.js +54 -0
- package/factory/orchestrator/dist/providers/schema-validate.js +152 -0
- package/factory/orchestrator/dist/providers/types.js +49 -0
- package/factory/orchestrator/dist/queue.js +263 -0
- package/factory/orchestrator/dist/quorum.js +347 -0
- package/factory/orchestrator/dist/quorumEscalations.js +132 -0
- package/factory/orchestrator/dist/results.js +65 -0
- package/factory/orchestrator/dist/roadmap.js +437 -0
- package/factory/orchestrator/dist/runtime.js +86 -0
- package/factory/orchestrator/dist/sameMistakeKpi.js +243 -0
- package/factory/orchestrator/dist/sandbox.js +165 -0
- package/factory/orchestrator/dist/scaffold.js +373 -0
- package/factory/orchestrator/dist/scheduler.js +408 -0
- package/factory/orchestrator/dist/schemas.js +195 -0
- package/factory/orchestrator/dist/security.js +222 -0
- package/factory/orchestrator/dist/severity.js +293 -0
- package/factory/orchestrator/dist/spec.js +376 -0
- package/factory/orchestrator/dist/specChange.js +497 -0
- package/factory/orchestrator/dist/stack.js +324 -0
- package/factory/orchestrator/dist/symbols.js +966 -0
- package/factory/orchestrator/dist/taskEvents.js +399 -0
- package/factory/orchestrator/dist/taskId.js +126 -0
- package/factory/orchestrator/dist/taxonomy.js +113 -0
- package/factory/orchestrator/dist/testSelect.js +129 -0
- package/factory/orchestrator/dist/testerAudit.js +264 -0
- package/factory/orchestrator/dist/testgate.js +171 -0
- package/factory/orchestrator/dist/usage.js +874 -0
- package/factory/orchestrator/dist/waivers.js +228 -0
- package/factory/orchestrator/dist/waveBudget.js +223 -0
- package/factory/orchestrator/dist/waveConcurrency.js +250 -0
- package/factory/orchestrator/dist/waveNext.js +210 -0
- package/factory/orchestrator/dist/waveSchedule.js +146 -0
- package/factory/orchestrator/dist/worktree.js +207 -0
- package/factory/orchestrator/drizzle/0000_broken_rockslide.sql +183 -0
- package/factory/orchestrator/drizzle/0001_luxuriant_zaladane.sql +1 -0
- package/factory/orchestrator/drizzle/0002_yellow_wild_pack.sql +8 -0
- package/factory/orchestrator/drizzle/0003_damp_riptide.sql +12 -0
- package/factory/orchestrator/drizzle/0004_broad_lady_vermin.sql +1 -0
- package/factory/orchestrator/drizzle/0005_romantic_jocasta.sql +2 -0
- package/factory/orchestrator/drizzle/0006_bent_madelyne_pryor.sql +16 -0
- package/factory/orchestrator/drizzle/0007_overjoyed_goliath.sql +1 -0
- package/factory/orchestrator/drizzle/0008_smart_iron_patriot.sql +2 -0
- package/factory/orchestrator/drizzle/0009_agents_epic_id.sql +2 -0
- package/factory/orchestrator/drizzle/0010_milestone_kind.sql +1 -0
- package/factory/orchestrator/drizzle/meta/_journal.json +83 -0
- package/factory/policies/budgets.yml +262 -0
- package/factory/policies/crosscheck.yml +308 -0
- package/factory/policies/delegation.yml +44 -0
- package/factory/policies/effort.yml +142 -0
- package/factory/policies/guardrails.yml +306 -0
- package/factory/policies/lessons.md +239 -0
- package/factory/policies/scheduler.yml +90 -0
- package/factory/policies/sensitive-paths.yml +148 -0
- package/factory/policies/severity.yml +83 -0
- package/factory/policies/stack.yml +60 -0
- package/factory/policies/taxonomy.yml +340 -0
- package/factory/policies/worktree.yml +95 -0
- package/factory/scaffold/base/.github/workflows/ci.yml +34 -0
- package/factory/scaffold/base/.gitignore.tmpl +11 -0
- package/factory/scaffold/base/AGENTS.md +33 -0
- package/factory/scaffold/base/README.md +25 -0
- package/factory/scaffold/base/biome.json.tmpl +30 -0
- package/factory/scaffold/base/package.json +25 -0
- package/factory/scaffold/base/pnpm-workspace.yaml.tmpl +16 -0
- package/factory/scaffold/base/src/index.ts +4 -0
- package/factory/scaffold/base/test/index.test.ts +8 -0
- package/factory/scaffold/base/tsconfig.json +20 -0
- package/factory/scaffold/base/tsconfig.test.json +9 -0
- package/factory/scaffold/base/vitest.config.ts +29 -0
- package/factory/scaffold/mcp/mcp.manifest.json +22 -0
- package/factory/scaffold/mcp/package.fragment.json +9 -0
- package/factory/scaffold/mcp/src/mcp/README.md +63 -0
- package/factory/scaffold/mcp/src/mcp/guard.ts +110 -0
- package/factory/scaffold/mcp/src/mcp/redact.ts +69 -0
- package/factory/scaffold/mcp/src/mcp/server.ts +55 -0
- package/factory/scaffold/mcp/src/mcp/tools/health.ts +60 -0
- package/factory/scaffold/mcp/test/mcp/guard.test.ts +108 -0
- package/factory/scaffold/mcp/test/mcp/redact.test.ts +61 -0
- package/factory/scaffold/mcp/test/mcp/surface.test.ts +100 -0
- package/factory/scaffold/ui/index.html +12 -0
- package/factory/scaffold/ui/package.fragment.json +13 -0
- package/factory/scaffold/ui/src/App.vue +10 -0
- package/factory/scaffold/ui/src/main.ts +5 -0
- package/factory/scaffold/ui/src/shims.d.ts +11 -0
- package/factory/scaffold/ui/vite.config.ts +20 -0
- package/factory/scaffold/ui-tailwind/package.fragment.json +6 -0
- package/factory/scaffold/ui-tailwind/vite.config.ts +26 -0
- package/factory/specs/schema/event.schema.json +82 -0
- package/factory/specs/schema/finding-evidence.schema.json +45 -0
- package/factory/specs/schema/finding.schema.json +115 -0
- package/factory/specs/schema/grader-verdict.schema.json +50 -0
- package/factory/specs/schema/judge-verdict.schema.json +19 -0
- package/factory/specs/schema/lesson.schema.json +85 -0
- package/factory/specs/schema/mcp-manifest.schema.json +230 -0
- package/factory/specs/schema/result.schema.json +81 -0
- package/factory/specs/schema/spec-change-request.schema.json +46 -0
- package/factory/specs/schema/task-spec.schema.json +134 -0
- package/package.json +98 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
// Drizzle schema for the SQLite projection layer (architecture §7, §10).
|
|
2
|
+
//
|
|
3
|
+
// Events (`state/events/*.jsonl`) are the source of truth; every table here
|
|
4
|
+
// is a DERIVED read-model rebuilt by db/projector.ts. Nothing outside the
|
|
5
|
+
// projector writes to these tables. Taxonomy-valued columns are stored as
|
|
6
|
+
// plain text — validation already happened at event-write time in events.ts
|
|
7
|
+
// (architecture §8: "the event logger rejects unknown tags at write time").
|
|
8
|
+
//
|
|
9
|
+
// One schema, both targets: this file is the single source for the
|
|
10
|
+
// orchestrator's local SQLite and for D1 later, via Drizzle. It describes
|
|
11
|
+
// this repo's own database, not whatever a scaffolded project answered for
|
|
12
|
+
// `database` in factory/policies/stack.yml.
|
|
13
|
+
import { index, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
|
14
|
+
/**
|
|
15
|
+
* Every event ever appended, exactly as logged — the append-only substrate mirrored 1:1.
|
|
16
|
+
*
|
|
17
|
+
* `project` (Phase 6b, architecture §8 note): a PLAIN STRING identifier, not
|
|
18
|
+
* a closed taxonomy vocabulary value — projects are opened/closed by the
|
|
19
|
+
* operator far more often than any §8 dimension, and forcing a taxonomy PR
|
|
20
|
+
* per new project would defeat the point of a multi-project hub. Nullable
|
|
21
|
+
* for migration safety (every event logged before this column existed has
|
|
22
|
+
* no value here); queries.ts's helpers COALESCE it to 'black-smith' so old
|
|
23
|
+
* rows and new single-project fixtures both resolve to the same default
|
|
24
|
+
* project rather than an ungrouped null bucket.
|
|
25
|
+
*/
|
|
26
|
+
export const eventsRaw = sqliteTable('events_raw', {
|
|
27
|
+
eventId: text('event_id').primaryKey(),
|
|
28
|
+
sessionId: text('session_id').notNull(),
|
|
29
|
+
ts: text('ts').notNull(),
|
|
30
|
+
eventType: text('event_type').notNull(),
|
|
31
|
+
taskId: text('task_id'),
|
|
32
|
+
agentId: text('agent_id'),
|
|
33
|
+
planVersion: integer('plan_version').notNull(),
|
|
34
|
+
causalParent: text('causal_parent'),
|
|
35
|
+
payload: text('payload').notNull(), // JSON
|
|
36
|
+
project: text('project'),
|
|
37
|
+
// Phase 6b: who wrote the event (EventRecord.actor — 'user', 'system', or
|
|
38
|
+
// an agent role/id), needed to tell an operator-authored decision event
|
|
39
|
+
// (Timeline's "Decisions" lens, architecture §8) apart from a system/
|
|
40
|
+
// agent one of the same event_type. Nullable for migration safety —
|
|
41
|
+
// events logged before this column existed simply can't be attributed.
|
|
42
|
+
actor: text('actor'),
|
|
43
|
+
}, (t) => [
|
|
44
|
+
index('events_raw_session_idx').on(t.sessionId),
|
|
45
|
+
index('events_raw_task_idx').on(t.taskId),
|
|
46
|
+
index('events_raw_type_idx').on(t.eventType),
|
|
47
|
+
index('events_raw_ts_idx').on(t.ts),
|
|
48
|
+
index('events_raw_project_idx').on(t.project),
|
|
49
|
+
]);
|
|
50
|
+
/** One row per session, folded from its session-start event + last-seen ts. */
|
|
51
|
+
export const sessions = sqliteTable('sessions', {
|
|
52
|
+
sessionId: text('session_id').primaryKey(),
|
|
53
|
+
startedAt: text('started_at').notNull(),
|
|
54
|
+
lastEventAt: text('last_event_at').notNull(),
|
|
55
|
+
eventCount: integer('event_count').notNull(),
|
|
56
|
+
});
|
|
57
|
+
/** `user_prompt` events (architecture §7), stored verbatim. */
|
|
58
|
+
export const prompts = sqliteTable('prompts', {
|
|
59
|
+
eventId: text('event_id').primaryKey(),
|
|
60
|
+
sessionId: text('session_id').notNull(),
|
|
61
|
+
ts: text('ts').notNull(),
|
|
62
|
+
prompt: text('prompt').notNull(),
|
|
63
|
+
causalParent: text('causal_parent'),
|
|
64
|
+
}, (t) => [index('prompts_session_idx').on(t.sessionId)]);
|
|
65
|
+
/** `dispatch_decision` events (architecture §7). */
|
|
66
|
+
export const dispatches = sqliteTable('dispatches', {
|
|
67
|
+
eventId: text('event_id').primaryKey(),
|
|
68
|
+
sessionId: text('session_id').notNull(),
|
|
69
|
+
ts: text('ts').notNull(),
|
|
70
|
+
taskId: text('task_id'),
|
|
71
|
+
agentId: text('agent_id'),
|
|
72
|
+
agentRole: text('agent_role').notNull(),
|
|
73
|
+
provider: text('provider').notNull(),
|
|
74
|
+
modelTier: text('model_tier').notNull(),
|
|
75
|
+
specRef: text('spec_ref'),
|
|
76
|
+
reason: text('reason'),
|
|
77
|
+
parentPromptId: text('parent_prompt_id'),
|
|
78
|
+
causalParent: text('causal_parent'),
|
|
79
|
+
project: text('project'), // Phase 6b — see eventsRaw's project comment above.
|
|
80
|
+
}, (t) => [
|
|
81
|
+
index('dispatches_session_idx').on(t.sessionId),
|
|
82
|
+
index('dispatches_task_idx').on(t.taskId),
|
|
83
|
+
index('dispatches_role_idx').on(t.agentRole),
|
|
84
|
+
index('dispatches_provider_idx').on(t.provider),
|
|
85
|
+
index('dispatches_model_tier_idx').on(t.modelTier),
|
|
86
|
+
index('dispatches_project_idx').on(t.project),
|
|
87
|
+
]);
|
|
88
|
+
/**
|
|
89
|
+
* Live agent registry (agents-registry.ts owns the fold semantics): one row
|
|
90
|
+
* per dispatch_decision, closed by whichever terminal event (task-result-
|
|
91
|
+
* recorded / judge-reported / error-logged) comes next for the same
|
|
92
|
+
* `(task_id, agent_role)`, superseded by a redispatch of that same pair
|
|
93
|
+
* before any terminal event arrives, or abandoned by the `epic-closed` that
|
|
94
|
+
* ended the run it belonged to (D-187). The pair, not `task_id` alone: `/bs run`
|
|
95
|
+
* puts a coder, a grader, a reviewer and a security-reviewer on one task at
|
|
96
|
+
* once (D-23/P9-12).
|
|
97
|
+
*/
|
|
98
|
+
export const agents = sqliteTable('agents', {
|
|
99
|
+
id: text('id').primaryKey(), // dispatch event_id
|
|
100
|
+
sessionId: text('session_id').notNull(),
|
|
101
|
+
taskId: text('task_id'),
|
|
102
|
+
/** The epic this agent works on: an epic-level dispatch names one and has no task (D-234). */
|
|
103
|
+
epicId: text('epic_id'),
|
|
104
|
+
agentId: text('agent_id'),
|
|
105
|
+
agentRole: text('agent_role').notNull(),
|
|
106
|
+
/** Dispatch round — 1 for a worker whose dispatch declares none. Carried, not keyed on. */
|
|
107
|
+
round: integer('round').notNull().default(1),
|
|
108
|
+
provider: text('provider').notNull(),
|
|
109
|
+
modelTier: text('model_tier').notNull(),
|
|
110
|
+
dispatchedAt: text('dispatched_at').notNull(),
|
|
111
|
+
terminalEventId: text('terminal_event_id'),
|
|
112
|
+
terminalAt: text('terminal_at'),
|
|
113
|
+
terminalType: text('terminal_type'), // 'result' | 'error' | 'superseded' | 'abandoned'
|
|
114
|
+
status: text('status').notNull(), // 'live' | 'done' | 'error' | 'superseded' | 'abandoned'
|
|
115
|
+
}, (t) => [
|
|
116
|
+
index('agents_session_idx').on(t.sessionId),
|
|
117
|
+
index('agents_status_idx').on(t.status),
|
|
118
|
+
index('agents_role_idx').on(t.agentRole),
|
|
119
|
+
index('agents_epic_idx').on(t.epicId),
|
|
120
|
+
]);
|
|
121
|
+
/** One row per task_id, folded from task-added, wave-admitted/merged, gate-outcome, and error events. */
|
|
122
|
+
export const tasks = sqliteTable('tasks', {
|
|
123
|
+
taskId: text('task_id').primaryKey(),
|
|
124
|
+
sessionId: text('session_id').notNull(),
|
|
125
|
+
epicId: text('epic_id'),
|
|
126
|
+
caseTag: text('case_tag'),
|
|
127
|
+
origin: text('origin'),
|
|
128
|
+
taskStatus: text('task_status').notNull(),
|
|
129
|
+
planVersion: integer('plan_version'),
|
|
130
|
+
objective: text('objective'),
|
|
131
|
+
claims: text('claims'), // JSON array
|
|
132
|
+
budgetTokens: integer('budget_tokens'),
|
|
133
|
+
branch: text('branch'),
|
|
134
|
+
createdAt: text('created_at').notNull(),
|
|
135
|
+
updatedAt: text('updated_at').notNull(),
|
|
136
|
+
project: text('project'), // Phase 6b — see eventsRaw's project comment above.
|
|
137
|
+
}, (t) => [
|
|
138
|
+
index('tasks_session_idx').on(t.sessionId),
|
|
139
|
+
index('tasks_epic_idx').on(t.epicId),
|
|
140
|
+
index('tasks_status_idx').on(t.taskStatus),
|
|
141
|
+
index('tasks_project_idx').on(t.project),
|
|
142
|
+
]);
|
|
143
|
+
/** `edge-recorded` events (architecture §7 dependency edges). */
|
|
144
|
+
export const edges = sqliteTable('edges', {
|
|
145
|
+
eventId: text('event_id').primaryKey(),
|
|
146
|
+
sessionId: text('session_id').notNull(),
|
|
147
|
+
ts: text('ts').notNull(),
|
|
148
|
+
taskId: text('task_id').notNull(),
|
|
149
|
+
dependsOn: text('depends_on').notNull(),
|
|
150
|
+
edgeType: text('edge_type').notNull(),
|
|
151
|
+
edgeProvenance: text('edge_provenance').notNull(),
|
|
152
|
+
}, (t) => [index('edges_session_idx').on(t.sessionId), index('edges_task_idx').on(t.taskId)]);
|
|
153
|
+
/** `error-logged` events. */
|
|
154
|
+
export const errors = sqliteTable('errors', {
|
|
155
|
+
eventId: text('event_id').primaryKey(),
|
|
156
|
+
sessionId: text('session_id').notNull(),
|
|
157
|
+
ts: text('ts').notNull(),
|
|
158
|
+
taskRef: text('task_ref'),
|
|
159
|
+
agentId: text('agent_id'),
|
|
160
|
+
errorGroup: text('error_group').notNull(),
|
|
161
|
+
errorClass: text('error_class').notNull(),
|
|
162
|
+
severity: text('severity').notNull(),
|
|
163
|
+
detail: text('detail'),
|
|
164
|
+
project: text('project'), // Phase 6b — see eventsRaw's project comment above.
|
|
165
|
+
}, (t) => [
|
|
166
|
+
index('errors_session_idx').on(t.sessionId),
|
|
167
|
+
index('errors_group_idx').on(t.errorGroup),
|
|
168
|
+
index('errors_severity_idx').on(t.severity),
|
|
169
|
+
index('errors_ts_idx').on(t.ts),
|
|
170
|
+
index('errors_project_idx').on(t.project),
|
|
171
|
+
]);
|
|
172
|
+
/** Current finding state — folded via findings.ts's listFindings(), REUSED not duplicated. */
|
|
173
|
+
export const findings = sqliteTable('findings', {
|
|
174
|
+
findingId: text('finding_id').primaryKey(),
|
|
175
|
+
sessionId: text('session_id').notNull(),
|
|
176
|
+
taskId: text('task_id').notNull(),
|
|
177
|
+
epicId: text('epic_id'),
|
|
178
|
+
fingerprint: text('fingerprint').notNull(),
|
|
179
|
+
findingCategory: text('finding_category').notNull(),
|
|
180
|
+
severity: text('severity').notNull(),
|
|
181
|
+
findingStatus: text('finding_status').notNull(),
|
|
182
|
+
summary: text('summary').notNull(),
|
|
183
|
+
foundBy: text('found_by').notNull(),
|
|
184
|
+
foundByProvider: text('found_by_provider'),
|
|
185
|
+
verifiedBy: text('verified_by'),
|
|
186
|
+
verifiedByProvider: text('verified_by_provider'),
|
|
187
|
+
sameMistakeOfLessonId: text('same_mistake_of_lesson_id'),
|
|
188
|
+
waiverId: text('waiver_id'),
|
|
189
|
+
raisedAt: text('raised_at').notNull(),
|
|
190
|
+
updatedAt: text('updated_at').notNull(),
|
|
191
|
+
project: text('project'), // Phase 6b — see eventsRaw's project comment above.
|
|
192
|
+
}, (t) => [
|
|
193
|
+
index('findings_session_idx').on(t.sessionId),
|
|
194
|
+
index('findings_task_idx').on(t.taskId),
|
|
195
|
+
index('findings_status_idx').on(t.findingStatus),
|
|
196
|
+
index('findings_severity_idx').on(t.severity),
|
|
197
|
+
index('findings_fingerprint_idx').on(t.fingerprint),
|
|
198
|
+
index('findings_project_idx').on(t.project),
|
|
199
|
+
]);
|
|
200
|
+
/** `waiver-granted` / `waiver-denied` events — folded via waivers.ts semantics, REUSED. */
|
|
201
|
+
export const waivers = sqliteTable('waivers', {
|
|
202
|
+
eventId: text('event_id').primaryKey(),
|
|
203
|
+
sessionId: text('session_id').notNull(),
|
|
204
|
+
ts: text('ts').notNull(),
|
|
205
|
+
fingerprint: text('fingerprint').notNull(),
|
|
206
|
+
decision: text('decision').notNull(), // 'granted' | 'denied'
|
|
207
|
+
operatorNote: text('operator_note'),
|
|
208
|
+
}, (t) => [
|
|
209
|
+
index('waivers_session_idx').on(t.sessionId),
|
|
210
|
+
index('waivers_fingerprint_idx').on(t.fingerprint),
|
|
211
|
+
]);
|
|
212
|
+
/**
|
|
213
|
+
* `lesson-candidate-raised` / `lesson-status-changed` events (Phase 5
|
|
214
|
+
* deviation — see db/projector.ts header comment; the full lessons loop is
|
|
215
|
+
* Phase 7, this table is forward-compatible with it).
|
|
216
|
+
*/
|
|
217
|
+
export const lessons = sqliteTable('lessons', {
|
|
218
|
+
lessonId: text('lesson_id').primaryKey(),
|
|
219
|
+
sessionId: text('session_id').notNull(),
|
|
220
|
+
lessonType: text('lesson_type').notNull(),
|
|
221
|
+
lessonLevel: text('lesson_level').notNull(),
|
|
222
|
+
lessonStatus: text('lesson_status').notNull(),
|
|
223
|
+
lessonScope: text('lesson_scope').notNull(),
|
|
224
|
+
statement: text('statement').notNull(),
|
|
225
|
+
validFrom: text('valid_from').notNull(),
|
|
226
|
+
supersededBy: text('superseded_by'),
|
|
227
|
+
invalidatedByEventId: text('invalidated_by_event_id'),
|
|
228
|
+
provenanceEventIds: text('provenance_event_ids'), // JSON array
|
|
229
|
+
evidence: text('evidence'),
|
|
230
|
+
timesPrevented: integer('times_prevented').notNull().default(0),
|
|
231
|
+
// Phase 7 (lessons.ts) — see lesson.schema.json's field comments: only
|
|
232
|
+
// meaningful for a `rule`-typed, claim-path/stack-wide-scoped entry;
|
|
233
|
+
// nullable, most lessons never set either.
|
|
234
|
+
findingCategory: text('finding_category'),
|
|
235
|
+
claimPath: text('claim_path'),
|
|
236
|
+
// D-129: the selectors the other two selector scopes filter on at
|
|
237
|
+
// dispatch. Nullable for the same reason claim_path is — each is
|
|
238
|
+
// meaningful for exactly one scope — and null on every lesson raised
|
|
239
|
+
// before the selectors existed.
|
|
240
|
+
agentRole: text('agent_role'),
|
|
241
|
+
caseType: text('case_type'),
|
|
242
|
+
}, (t) => [
|
|
243
|
+
index('lessons_session_idx').on(t.sessionId),
|
|
244
|
+
index('lessons_status_idx').on(t.lessonStatus),
|
|
245
|
+
]);
|
|
246
|
+
/**
|
|
247
|
+
* `epic-closed` events (D-43/D-44/P9-27). One row per closed epic — an epic
|
|
248
|
+
* has no other lifecycle event, so there is no "open" row here and absence
|
|
249
|
+
* means "not closed". Keyed on the payload's `epic_id`, never on task_id:
|
|
250
|
+
* the hand-written dogfood close used `<epic>/epic` as its task_id, which is
|
|
251
|
+
* not the reserved suffix, so anything routing through the task fold would
|
|
252
|
+
* have minted a phantom task card for it.
|
|
253
|
+
*/
|
|
254
|
+
export const epics = sqliteTable('epics', {
|
|
255
|
+
epicId: text('epic_id').primaryKey(),
|
|
256
|
+
sessionId: text('session_id').notNull(),
|
|
257
|
+
epicStatus: text('epic_status').notNull(),
|
|
258
|
+
/** 'verdict' | 'operator-override' — who the close is attributable to. */
|
|
259
|
+
closedBy: text('closed_by').notNull(),
|
|
260
|
+
/** What the machine said, kept even when a human closed against it. */
|
|
261
|
+
machineVerdict: text('machine_verdict'),
|
|
262
|
+
machineReason: text('machine_reason'),
|
|
263
|
+
overrideRationale: text('override_rationale'),
|
|
264
|
+
blockers: text('blockers'), // JSON array
|
|
265
|
+
closedAt: text('closed_at').notNull(),
|
|
266
|
+
eventId: text('event_id').notNull(),
|
|
267
|
+
project: text('project'),
|
|
268
|
+
}, (t) => [index('epics_session_idx').on(t.sessionId), index('epics_project_idx').on(t.project)]);
|
|
269
|
+
/**
|
|
270
|
+
* Parsed from `factory/specs/roadmap.md` (roadmap.ts) — NOT session-scoped:
|
|
271
|
+
* one global roadmap, fully replaced (delete-all + reinsert) on every
|
|
272
|
+
* rebuild()/apply() call by db/projector.ts's projectMilestones(). Cheap:
|
|
273
|
+
* a handful of rows, re-parsed from a small committed file every time.
|
|
274
|
+
*/
|
|
275
|
+
export const milestones = sqliteTable('milestones', {
|
|
276
|
+
milestoneId: text('milestone_id').primaryKey(),
|
|
277
|
+
name: text('name').notNull(),
|
|
278
|
+
status: text('status').notNull(), // 'planned' | 'in-progress' | 'completed'
|
|
279
|
+
sequence: integer('sequence').notNull(),
|
|
280
|
+
goal: text('goal'),
|
|
281
|
+
epicIds: text('epic_ids').notNull(), // JSON array
|
|
282
|
+
// Phase 6b — see eventsRaw's project comment above. roadmap.ts defaults
|
|
283
|
+
// an unspecified `- project:` bullet to 'black-smith' at parse time (not
|
|
284
|
+
// left null here), since factory/specs/roadmap.md (ROADMAP_PATH) is a
|
|
285
|
+
// hand-authored declaration, not an event replay — there is no "old row"
|
|
286
|
+
// to migrate.
|
|
287
|
+
project: text('project').notNull().default('black-smith'),
|
|
288
|
+
// Phase 10 -- 'factory' | 'dogfood' | 'product' (roadmap.ts's
|
|
289
|
+
// MilestoneKind). Defaults to 'factory' here for the same reason project
|
|
290
|
+
// defaults to 'black-smith': the column default has to agree with what
|
|
291
|
+
// roadmap.ts resolves for a milestone that declares neither bullet, and
|
|
292
|
+
// for those two that answer is the factory's own.
|
|
293
|
+
kind: text('kind').notNull().default('factory'),
|
|
294
|
+
}, (t) => [index('milestones_project_idx').on(t.project)]);
|
|
295
|
+
/** One row per artifact entry on a `task-result-recorded` event's payload. */
|
|
296
|
+
export const artifacts = sqliteTable('artifacts', {
|
|
297
|
+
id: text('id').primaryKey(), // `${event_id}#${index}`
|
|
298
|
+
sessionId: text('session_id').notNull(),
|
|
299
|
+
taskId: text('task_id').notNull(),
|
|
300
|
+
eventId: text('event_id').notNull(),
|
|
301
|
+
ts: text('ts').notNull(),
|
|
302
|
+
type: text('type').notNull(),
|
|
303
|
+
path: text('path').notNull(),
|
|
304
|
+
description: text('description'),
|
|
305
|
+
}, (t) => [index('artifacts_session_idx').on(t.sessionId), index('artifacts_task_idx').on(t.taskId)]);
|