@cleocode/skills 2026.4.4 → 2026.4.6
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/package.json +1 -1
- package/skills/ct-adr-recorder/SKILL.md +175 -0
- package/skills/ct-adr-recorder/manifest-entry.json +30 -0
- package/skills/ct-adr-recorder/references/cascade.md +82 -0
- package/skills/ct-adr-recorder/references/examples.md +141 -0
- package/skills/ct-artifact-publisher/SKILL.md +146 -0
- package/skills/ct-artifact-publisher/manifest-entry.json +30 -0
- package/skills/ct-artifact-publisher/references/artifact-types.md +126 -0
- package/skills/ct-artifact-publisher/references/handler-interface.md +187 -0
- package/skills/ct-consensus-voter/SKILL.md +158 -0
- package/skills/ct-consensus-voter/manifest-entry.json +30 -0
- package/skills/ct-consensus-voter/references/matrix-examples.md +140 -0
- package/skills/ct-grade/references/token-tracking.md +2 -2
- package/skills/ct-grade/scripts/run_all.py +1 -1
- package/skills/ct-grade-v2-1/manifest-entry.json +1 -1
- package/skills/ct-ivt-looper/SKILL.md +181 -0
- package/skills/ct-ivt-looper/manifest-entry.json +30 -0
- package/skills/ct-ivt-looper/references/escalation.md +91 -0
- package/skills/ct-ivt-looper/references/frameworks.md +119 -0
- package/skills/ct-ivt-looper/references/loop-anatomy.md +156 -0
- package/skills/ct-orchestrator/manifest-entry.json +1 -1
- package/skills/ct-provenance-keeper/SKILL.md +161 -0
- package/skills/ct-provenance-keeper/manifest-entry.json +30 -0
- package/skills/ct-provenance-keeper/references/signing.md +188 -0
- package/skills/ct-provenance-keeper/references/slsa.md +121 -0
- package/skills/ct-release-orchestrator/SKILL.md +134 -0
- package/skills/ct-release-orchestrator/manifest-entry.json +30 -0
- package/skills/ct-release-orchestrator/references/composition.md +138 -0
- package/skills/ct-release-orchestrator/references/release-types.md +130 -0
- package/skills/ct-skill-creator/manifest-entry.json +1 -1
- package/skills/ct-skill-creator/references/provider-deployment.md +9 -9
- package/skills/ct-skill-validator/evals/evals.json +1 -1
- package/skills/ct-skill-validator/manifest-entry.json +1 -1
- package/skills/manifest.json +252 -16
- package/skills/ct-skill-creator/.cleo/.context-state.json +0 -13
package/package.json
CHANGED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ct-adr-recorder
|
|
3
|
+
description: "Records Architecture Decision Records from accepted consensus verdicts. Use when promoting a consensus outcome to a formal ADR: drafts the document in the proposed-then-accepted HITL lifecycle, links to the originating consensus manifest, persists the decision to the canonical SQLite decisions table, and triggers downstream invalidation when an accepted ADR is later superseded. Triggers on phrases like 'write ADR', 'record architecture decision', 'formalize this decision', 'lock in the choice', 'create ADR-XXX', or when a consensus task reaches completed status and needs formalization."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ADR Recorder
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Drafts, persists, and lifecycles Architecture Decision Records (ADRs) derived from accepted consensus verdicts. The skill owns the proposed-then-accepted HITL gate, writes the canonical markdown artifact, inserts the record into the SQLite `decisions` table via Drizzle, and orchestrates downstream invalidation whenever an accepted ADR is later superseded.
|
|
11
|
+
|
|
12
|
+
## Core Principle
|
|
13
|
+
|
|
14
|
+
> ADRs capture decisions from consensus verdicts, never from the author's own judgment.
|
|
15
|
+
|
|
16
|
+
## Immutable Constraints
|
|
17
|
+
|
|
18
|
+
| ID | Rule | Enforcement |
|
|
19
|
+
|----|------|-------------|
|
|
20
|
+
| ADR-001 | ADR MUST be generated from an accepted consensus report verdict. | `validateArchitectureDecisionProtocol` rejects entries without `consensus_manifest_id`; missing link deducts 25 from score. |
|
|
21
|
+
| ADR-002 | ADR MUST include a `consensus_manifest_id` field linking to the originating consensus. | Manifest entry field is required. |
|
|
22
|
+
| ADR-003 | ADR MUST require explicit HITL approval to transition from `proposed` to `accepted`. | `hitlReviewed: false` with `status: accepted` is rejected; exit code 65 (HANDOFF_REQUIRED). |
|
|
23
|
+
| ADR-004 | ADR MUST include Context, Options Evaluated, Decision, Rationale, and Consequences sections. | Regex check on the ADR body; missing section deducts 20 from score. |
|
|
24
|
+
| ADR-005 | Superseded ADRs MUST trigger downstream invalidation of linked Specifications, Decompositions, and Implementations. | `downstreamFlagged: false` on `status: superseded` fails validation; exit code 18 (CASCADE_FAILED). |
|
|
25
|
+
| ADR-006 | ADR MUST be persisted in the canonical `decisions` SQLite table via Drizzle ORM. | `persistedInDb: false` rejects the manifest entry. |
|
|
26
|
+
| ADR-007 | Manifest entry MUST set `agent_type: "decision"`. | Validator rejects any other value. |
|
|
27
|
+
| ADR-008 | ADR MUST block the Specification stage until status is `accepted`. | Lifecycle state machine refuses to advance past the ADR stage while status is `proposed`. |
|
|
28
|
+
|
|
29
|
+
## Status Lifecycle
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
proposed --HITL review--> accepted --supersession--> superseded
|
|
33
|
+
|
|
|
34
|
+
+------deprecation------> deprecated
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
| Status | Transition From | Required Input | Effect |
|
|
38
|
+
|--------|-----------------|----------------|--------|
|
|
39
|
+
| `proposed` | (initial draft) | Consensus manifest id | Pipeline pauses; exit 65 HANDOFF_REQUIRED |
|
|
40
|
+
| `accepted` | `proposed` | Human review signal | Unblocks Specification stage |
|
|
41
|
+
| `superseded` | `accepted` | New ADR id | Fires downstream cascade (see references/cascade.md) |
|
|
42
|
+
| `deprecated` | `accepted` | Deprecation reason | Removed from canon without replacement |
|
|
43
|
+
|
|
44
|
+
The `proposed -> accepted` edge is the only HITL gate in the pipeline. A human reviewer MUST explicitly sign off; auto-promotion is forbidden.
|
|
45
|
+
|
|
46
|
+
## ADR Document Structure
|
|
47
|
+
|
|
48
|
+
Every ADR markdown artifact MUST carry frontmatter plus six canonical sections. Keep sections 1-5 concise; prose belongs in the downstream spec, not the ADR.
|
|
49
|
+
|
|
50
|
+
```markdown
|
|
51
|
+
---
|
|
52
|
+
id: ADR-0042
|
|
53
|
+
title: "Adopt Drizzle ORM v1 beta for all SQLite access"
|
|
54
|
+
status: proposed
|
|
55
|
+
date: 2026-04-06
|
|
56
|
+
consensus_manifest_id: CONS-2026-04-06-0017
|
|
57
|
+
supersedes: []
|
|
58
|
+
superseded_by: []
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
# ADR-0042: Adopt Drizzle ORM v1 beta for all SQLite access
|
|
62
|
+
|
|
63
|
+
## 1. Context and Problem Statement
|
|
64
|
+
Better-sqlite3 and raw drizzle 0.x diverge on schema introspection and block
|
|
65
|
+
forward migration of the `decisions` table.
|
|
66
|
+
|
|
67
|
+
## 2. Options Evaluated
|
|
68
|
+
* Option A: Stay on drizzle 0.29 and backport fixes.
|
|
69
|
+
* Option B: Move to drizzle 1.0.0-beta and accept API churn.
|
|
70
|
+
* Option C: Drop Drizzle, switch to Kysely.
|
|
71
|
+
|
|
72
|
+
## 3. Decision
|
|
73
|
+
Adopt drizzle-orm@1.0.0-beta project-wide; pin to a single beta tag.
|
|
74
|
+
|
|
75
|
+
## 4. Rationale
|
|
76
|
+
Derived from CONS-2026-04-06-0017 (verdict PROVEN, 0.82 confidence).
|
|
77
|
+
Option B preserves relational queries and unblocks the migration epic.
|
|
78
|
+
|
|
79
|
+
## 5. Consequences
|
|
80
|
+
### Positive
|
|
81
|
+
* Single ORM path; no downgrades.
|
|
82
|
+
### Negative
|
|
83
|
+
* API churn in each beta; pin required per release.
|
|
84
|
+
|
|
85
|
+
## 6. Downstream Impact (Traceability)
|
|
86
|
+
Flags specs T4776, T4781; decomposition epic T4772; live impl T4790.
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
A longer, realistic example with all six sections filled out lives in [references/examples.md](references/examples.md).
|
|
90
|
+
|
|
91
|
+
## HITL Approval Gate
|
|
92
|
+
|
|
93
|
+
When a draft reaches `proposed`, the skill MUST:
|
|
94
|
+
|
|
95
|
+
1. Write the markdown artifact to disk.
|
|
96
|
+
2. Record the manifest entry with `status: proposed` and `agent_type: "decision"`.
|
|
97
|
+
3. Exit with code 65 (`HANDOFF_REQUIRED`).
|
|
98
|
+
4. Leave the pipeline paused until a human reviewer runs the approval path.
|
|
99
|
+
|
|
100
|
+
The agent MUST NOT:
|
|
101
|
+
|
|
102
|
+
- Promote a `proposed` ADR to `accepted` on its own.
|
|
103
|
+
- Retry the transition on a loop after exit 65.
|
|
104
|
+
- Edit the ADR body after exit 65 (any revision starts a new `proposed` cycle).
|
|
105
|
+
|
|
106
|
+
The human reviewer is expected to:
|
|
107
|
+
|
|
108
|
+
1. Read the markdown and the linked consensus manifest.
|
|
109
|
+
2. Confirm that every option from the consensus verdict appears in section 2.
|
|
110
|
+
3. Sign off by moving the status to `accepted` through the CLI and re-running validation with `hitlReviewed: true`.
|
|
111
|
+
|
|
112
|
+
## Downstream Cascade (on supersession)
|
|
113
|
+
|
|
114
|
+
When an accepted ADR is later superseded, the skill MUST:
|
|
115
|
+
|
|
116
|
+
1. Query the `decision_evidence` relation for every specification, decomposition, and implementation that cited the old ADR.
|
|
117
|
+
2. Flag each linked artifact as `needs-review`.
|
|
118
|
+
3. Suspend any active implementation or contribution task tied to the old ADR.
|
|
119
|
+
4. Record the cascade in the new ADR's manifest entry.
|
|
120
|
+
|
|
121
|
+
A missing cascade fails validation with exit code 18 (`CASCADE_FAILED`). The full flow, including the `decision_evidence` query and the manifest fields to populate, is documented in [references/cascade.md](references/cascade.md).
|
|
122
|
+
|
|
123
|
+
## Integration
|
|
124
|
+
|
|
125
|
+
Validate every ADR manifest entry through `cleo check protocol`:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Draft reaches proposed: runs inside the skill, before HITL hand-off.
|
|
129
|
+
cleo check protocol \
|
|
130
|
+
--protocolType architecture-decision \
|
|
131
|
+
--taskId T4798 \
|
|
132
|
+
--status proposed \
|
|
133
|
+
--persistedInDb true \
|
|
134
|
+
--adrContent "$(cat docs/adr/ADR-0042.md)"
|
|
135
|
+
|
|
136
|
+
# HITL accepts the ADR: rerun with the review flag.
|
|
137
|
+
cleo check protocol \
|
|
138
|
+
--protocolType architecture-decision \
|
|
139
|
+
--taskId T4798 \
|
|
140
|
+
--status accepted \
|
|
141
|
+
--hitlReviewed true \
|
|
142
|
+
--persistedInDb true
|
|
143
|
+
|
|
144
|
+
# Later supersession: include the cascade flag.
|
|
145
|
+
cleo check protocol \
|
|
146
|
+
--protocolType architecture-decision \
|
|
147
|
+
--taskId T4798 \
|
|
148
|
+
--status superseded \
|
|
149
|
+
--downstreamFlagged true
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Exit code 0 = valid. Exit code 65 = `HANDOFF_REQUIRED`. Exit code 18 = `CASCADE_FAILED`. Exit code 84 = `PROVENANCE_REQUIRED` (attempted ADR without a linked consensus).
|
|
153
|
+
|
|
154
|
+
## Anti-Patterns
|
|
155
|
+
|
|
156
|
+
| Pattern | Problem | Solution |
|
|
157
|
+
|---------|---------|----------|
|
|
158
|
+
| Drafting an ADR without a consensus verdict | Violates ADR-001; decision lacks evidence base | Run the consensus skill first; copy the manifest id into the ADR frontmatter |
|
|
159
|
+
| Auto-promoting `proposed` to `accepted` | Bypasses the HITL gate (ADR-003) | Stop at exit 65 and wait for the human reviewer |
|
|
160
|
+
| Persisting only the markdown, skipping SQLite | Violates ADR-006; loses relational queries | Insert via the `architectureDecisions` Drizzle table before exiting the skill |
|
|
161
|
+
| Omitting the Downstream Impact section | Future implementers can't find cascade targets (ADR-005) | Populate section 6 with every touched spec/epic/impl |
|
|
162
|
+
| Using the ADR to list implementation requirements | Blurs the ADR/spec boundary | Keep the ADR decision-only; push requirements to the specification stage |
|
|
163
|
+
| Superseding without running the cascade | Violates ADR-005; breaks the evidence chain | Query `decision_evidence`, flag artifacts, record the cascade in the new ADR |
|
|
164
|
+
| Editing an accepted ADR in-place | Breaks immutability and audit trail | Create a new ADR that supersedes the old one |
|
|
165
|
+
|
|
166
|
+
## Critical Rules Summary
|
|
167
|
+
|
|
168
|
+
1. ADRs MUST be drafted from an accepted consensus verdict, with `consensus_manifest_id` populated.
|
|
169
|
+
2. The `proposed -> accepted` transition MUST pass through a HITL review; agents stop at exit 65.
|
|
170
|
+
3. The ADR body MUST contain all five canonical sections (Context, Options, Decision, Rationale, Consequences).
|
|
171
|
+
4. The decision MUST be inserted into the canonical `decisions` SQLite table via Drizzle.
|
|
172
|
+
5. The manifest entry MUST set `agent_type: "decision"` and reference the output markdown file.
|
|
173
|
+
6. Superseding an accepted ADR MUST trigger the downstream cascade over linked specs, decomps, and impls.
|
|
174
|
+
7. Agents MUST NOT retry the HITL handoff on a loop; wait for the human reviewer.
|
|
175
|
+
8. Always validate via `cleo check protocol --protocolType architecture-decision` before exiting.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "CLEO-only metadata -- add to packages/skills/skills/manifest.json",
|
|
3
|
+
"name": "ct-adr-recorder",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"tier": 2,
|
|
6
|
+
"token_budget": 8000,
|
|
7
|
+
"protocol": "architecture-decision",
|
|
8
|
+
"capabilities": {
|
|
9
|
+
"inputs": ["consensus-manifest-id", "task-id", "decision-context"],
|
|
10
|
+
"outputs": ["adr-markdown", "decisions-table-row", "manifest-entry"],
|
|
11
|
+
"dispatch_triggers": [
|
|
12
|
+
"write ADR",
|
|
13
|
+
"record architecture decision",
|
|
14
|
+
"formalize this decision",
|
|
15
|
+
"create ADR",
|
|
16
|
+
"lock in the choice"
|
|
17
|
+
],
|
|
18
|
+
"compatible_subagent_types": ["general-purpose"],
|
|
19
|
+
"chains_to": ["ct-consensus-voter", "ct-spec-writer"],
|
|
20
|
+
"dispatch_keywords": {
|
|
21
|
+
"primary": ["adr", "decision", "architecture", "formalize"],
|
|
22
|
+
"secondary": ["proposed", "accepted", "superseded", "hitl"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"constraints": {
|
|
26
|
+
"max_context_tokens": 60000,
|
|
27
|
+
"requires_session": false,
|
|
28
|
+
"requires_epic": false
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Downstream Cascade Flow
|
|
2
|
+
|
|
3
|
+
When an `accepted` ADR is superseded, the cascade skill MUST reach every artifact that cites the old decision and flag it for review. This is the mechanism enforced by ADR-005.
|
|
4
|
+
|
|
5
|
+
## Cascade Trigger
|
|
6
|
+
|
|
7
|
+
The cascade fires on exactly one transition:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
accepted --> superseded
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
No other transition (deprecation, rewrite, revision) runs the cascade. Deprecation marks the ADR stale without replacing it and does not invalidate downstream work.
|
|
14
|
+
|
|
15
|
+
## Query Model
|
|
16
|
+
|
|
17
|
+
The canonical source of linkage is the `decision_evidence` relation in the SQLite schema. Every downstream artifact that relied on an ADR MUST have inserted a row at the time it was created.
|
|
18
|
+
|
|
19
|
+
```sql
|
|
20
|
+
SELECT artifact_type, artifact_id, cited_section, cited_at
|
|
21
|
+
FROM decision_evidence
|
|
22
|
+
WHERE decision_id = :old_adr_id
|
|
23
|
+
AND superseded_at IS NULL;
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
| Column | Meaning |
|
|
27
|
+
|--------|---------|
|
|
28
|
+
| `artifact_type` | `specification` / `decomposition` / `implementation` / `contribution` |
|
|
29
|
+
| `artifact_id` | Task id (`T####`) or spec id |
|
|
30
|
+
| `cited_section` | Which section of the ADR the artifact depended on |
|
|
31
|
+
| `cited_at` | Timestamp of the link |
|
|
32
|
+
| `superseded_at` | Set by the cascade when this row is flagged |
|
|
33
|
+
|
|
34
|
+
## Cascade Steps
|
|
35
|
+
|
|
36
|
+
1. **Query**: Run the query above. If the result set is empty, record `cascadeTargets: []` in the new ADR and continue — no downstream work exists.
|
|
37
|
+
2. **Classify**: Group rows by `artifact_type`. Specifications and decompositions get flagged `needs-review`. Implementations and contributions get suspended if currently active.
|
|
38
|
+
3. **Flag**: For each target, write the `needs-review` status to the task record and log the cascade manifest id.
|
|
39
|
+
4. **Suspend**: Any `active` implementation task MUST move to `blocked` with blocker `adr-superseded`. Active contribution records MUST attach a `contested` note citing the new ADR.
|
|
40
|
+
5. **Update** `decision_evidence`: Set `superseded_at = now()` on every flagged row.
|
|
41
|
+
6. **Record** in the new ADR's manifest entry:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"agent_type": "decision",
|
|
46
|
+
"status": "accepted",
|
|
47
|
+
"consensus_manifest_id": "CONS-2026-04-10-0021",
|
|
48
|
+
"supersedes": ["ADR-0042"],
|
|
49
|
+
"cascadeTargets": [
|
|
50
|
+
{"artifact_type": "specification", "artifact_id": "T4776", "action": "flagged"},
|
|
51
|
+
{"artifact_type": "implementation", "artifact_id": "T4790", "action": "suspended"}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Cascade Failures
|
|
57
|
+
|
|
58
|
+
Exit code 18 (`CASCADE_FAILED`) fires when any of the following occur:
|
|
59
|
+
|
|
60
|
+
| Failure | Remediation |
|
|
61
|
+
|---------|-------------|
|
|
62
|
+
| Query returns rows but `cascadeTargets` is empty in the manifest | Populate `cascadeTargets` and rerun validation |
|
|
63
|
+
| A downstream task refuses the status transition | Inspect task state; resolve manually before retrying |
|
|
64
|
+
| `decision_evidence.superseded_at` could not be written | Check Drizzle transaction; do not split into partial writes |
|
|
65
|
+
| The new ADR does not list the old ADR in `supersedes[]` | Add the reference and rerun |
|
|
66
|
+
|
|
67
|
+
The cascade is a single atomic step from the lifecycle's point of view: either every downstream artifact is flagged or the supersession is rejected. Partial cascades are never acceptable.
|
|
68
|
+
|
|
69
|
+
## Suspension and Resume
|
|
70
|
+
|
|
71
|
+
A suspended implementation task stays blocked until:
|
|
72
|
+
|
|
73
|
+
1. The spec that cited the old ADR is updated against the new ADR.
|
|
74
|
+
2. The decomposition epic is re-planned.
|
|
75
|
+
3. The implementation is re-attached to the new ADR via a fresh `decision_evidence` row.
|
|
76
|
+
4. A human reviewer signs off the unblock.
|
|
77
|
+
|
|
78
|
+
The skill does not auto-resume suspended work. That is deliberately out of scope — reconciliation is the Specification and Decomposition stages' job.
|
|
79
|
+
|
|
80
|
+
## Relation to the HITL Gate
|
|
81
|
+
|
|
82
|
+
The supersession path does not go through the HITL gate at the `superseded` transition. HITL review happened once, when the new ADR was promoted from `proposed` to `accepted`. That review MUST have examined the cascade plan; the cascade itself is mechanical and runs without a second human pause.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# ADR Examples
|
|
2
|
+
|
|
3
|
+
Full, realistic ADR artifact. Use as a copy-paste starting point; replace every field before committing.
|
|
4
|
+
|
|
5
|
+
## Example: ADR-0042 (Adopt Drizzle ORM v1 beta)
|
|
6
|
+
|
|
7
|
+
```markdown
|
|
8
|
+
---
|
|
9
|
+
id: ADR-0042
|
|
10
|
+
title: "Adopt Drizzle ORM v1 beta for all SQLite access"
|
|
11
|
+
status: proposed
|
|
12
|
+
date: 2026-04-06
|
|
13
|
+
consensus_manifest_id: CONS-2026-04-06-0017
|
|
14
|
+
supersedes: []
|
|
15
|
+
superseded_by: []
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# ADR-0042: Adopt Drizzle ORM v1 beta for all SQLite access
|
|
19
|
+
|
|
20
|
+
## 1. Context and Problem Statement
|
|
21
|
+
|
|
22
|
+
The CLEO monorepo currently pins `drizzle-orm@0.29.x`. That line diverges from
|
|
23
|
+
the v1 beta schema introspection model and no longer supports the `defineRelations`
|
|
24
|
+
primitive we need for the `decision_evidence` cascade query. Backporting patches
|
|
25
|
+
is feasible but compounds tech debt for every new migration. The consensus skill
|
|
26
|
+
(T4797) produced a PROVEN verdict at 0.82 confidence recommending immediate
|
|
27
|
+
migration to the v1 beta line.
|
|
28
|
+
|
|
29
|
+
## 2. Options Evaluated
|
|
30
|
+
|
|
31
|
+
The consensus skill evaluated three options:
|
|
32
|
+
|
|
33
|
+
* **Option A**: Stay on `drizzle-orm@0.29` and backport v1 schema fixes into a
|
|
34
|
+
fork. Low risk in the short term; high tech debt curve.
|
|
35
|
+
* **Option B**: Move the project to `drizzle-orm@1.0.0-beta` pinned to a single
|
|
36
|
+
beta tag per release, accept API churn, migrate one package per wave.
|
|
37
|
+
* **Option C**: Drop Drizzle entirely and move all SQLite access to Kysely.
|
|
38
|
+
Cleanest long-term abstraction but invalidates the entire migrations
|
|
39
|
+
directory and loses eight months of tooling.
|
|
40
|
+
|
|
41
|
+
## 3. Decision
|
|
42
|
+
|
|
43
|
+
Adopt `drizzle-orm@1.0.0-beta` across every package that touches SQLite. Each
|
|
44
|
+
release pins exactly one beta tag. Rollbacks happen per package, never per
|
|
45
|
+
release.
|
|
46
|
+
|
|
47
|
+
## 4. Rationale
|
|
48
|
+
|
|
49
|
+
Derived from CONS-2026-04-06-0017 (verdict PROVEN, 0.82 confidence). Three
|
|
50
|
+
agents voted Option B with high confidence, one voted Option A, none voted
|
|
51
|
+
Option C. The deciding evidence was the `defineRelations` primitive's ability
|
|
52
|
+
to express the `decision_evidence` cascade in a single declarative pass, which
|
|
53
|
+
the 0.29 line cannot do. The dissenting Option-A vote flagged API churn risk,
|
|
54
|
+
which is mitigated by the per-release pin in the Decision section.
|
|
55
|
+
|
|
56
|
+
## 5. Consequences
|
|
57
|
+
|
|
58
|
+
### Positive
|
|
59
|
+
|
|
60
|
+
* Single ORM path across the monorepo; no per-package downgrades.
|
|
61
|
+
* `defineRelations` unblocks the cascade query this ADR depends on.
|
|
62
|
+
* Migrations directory stays canonical.
|
|
63
|
+
|
|
64
|
+
### Negative
|
|
65
|
+
|
|
66
|
+
* Every beta release requires a compatibility review before pin bump.
|
|
67
|
+
* Type surface changes per beta; downstream packages must rebuild.
|
|
68
|
+
* No long-term stability guarantee from upstream until the beta closes.
|
|
69
|
+
|
|
70
|
+
## 6. Downstream Impact (Traceability)
|
|
71
|
+
|
|
72
|
+
The following artifacts are flagged as directly dependent on this ADR and MUST
|
|
73
|
+
be updated or re-validated when the decision lands:
|
|
74
|
+
|
|
75
|
+
| Artifact | Type | Reason |
|
|
76
|
+
|----------|------|--------|
|
|
77
|
+
| T4776 | specification | Defines the `decisions` table schema; must adopt v1 primitives |
|
|
78
|
+
| T4781 | specification | Defines the `decision_evidence` relation |
|
|
79
|
+
| T4772 | decomposition | Epic that owns the migration waves |
|
|
80
|
+
| T4790 | implementation | Live work on the decisions migration path |
|
|
81
|
+
|
|
82
|
+
Rejected alternatives remain in the manifest for institutional memory but MUST
|
|
83
|
+
NOT be cited by any downstream artifact.
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Example: ADR-0043 (Deprecate ADR-0042)
|
|
87
|
+
|
|
88
|
+
A deprecation ADR removes a decision from canon without replacing it. No downstream cascade runs; the `decision_evidence` rows stay live because nothing supersedes them.
|
|
89
|
+
|
|
90
|
+
```markdown
|
|
91
|
+
---
|
|
92
|
+
id: ADR-0043
|
|
93
|
+
title: "Deprecate Drizzle v1 adoption decision"
|
|
94
|
+
status: deprecated
|
|
95
|
+
date: 2026-05-12
|
|
96
|
+
consensus_manifest_id: CONS-2026-05-12-0003
|
|
97
|
+
supersedes: []
|
|
98
|
+
superseded_by: []
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
# ADR-0043: Deprecate Drizzle v1 adoption decision
|
|
102
|
+
|
|
103
|
+
## 1. Context and Problem Statement
|
|
104
|
+
|
|
105
|
+
Upstream has frozen the v1 beta line without a GA date. The migration planned
|
|
106
|
+
in ADR-0042 is paused pending a new decision path.
|
|
107
|
+
|
|
108
|
+
## 2. Options Evaluated
|
|
109
|
+
|
|
110
|
+
* Option A: Supersede ADR-0042 with a new ORM choice.
|
|
111
|
+
* Option B: Deprecate ADR-0042 without replacement and defer the decision.
|
|
112
|
+
|
|
113
|
+
## 3. Decision
|
|
114
|
+
|
|
115
|
+
Deprecate ADR-0042 without replacement. Downstream specs remain stable; no
|
|
116
|
+
cascade fires.
|
|
117
|
+
|
|
118
|
+
## 4. Rationale
|
|
119
|
+
|
|
120
|
+
Derived from CONS-2026-05-12-0003. No replacement is ready; forcing a
|
|
121
|
+
supersession would produce a contested cascade.
|
|
122
|
+
|
|
123
|
+
## 5. Consequences
|
|
124
|
+
|
|
125
|
+
### Positive
|
|
126
|
+
* Downstream work on v0.29 is not invalidated.
|
|
127
|
+
|
|
128
|
+
### Negative
|
|
129
|
+
* `defineRelations` work stays blocked until a future ADR is authored.
|
|
130
|
+
|
|
131
|
+
## 6. Downstream Impact (Traceability)
|
|
132
|
+
|
|
133
|
+
None. Deprecation is a canon-only operation.
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Things to Notice
|
|
137
|
+
|
|
138
|
+
- Frontmatter `supersedes` and `superseded_by` are always arrays, even when empty.
|
|
139
|
+
- The `consensus_manifest_id` in the frontmatter MUST match the id in the manifest entry; the validator cross-checks.
|
|
140
|
+
- Section 6 is the only section that links to tasks by id. Sections 1-5 stay prose-only.
|
|
141
|
+
- Rejected alternatives live in section 2, not in a separate "rejected" section, so they travel with the options list forever.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ct-artifact-publisher
|
|
3
|
+
description: "Builds and publishes artifacts to registries (npm, PyPI, cargo, docker, GitHub releases, generic tarballs) following the validate, then dry-run, then build, then publish, then record-provenance pipeline. Invoked by ct-release-orchestrator as a sub-skill when a release has artifact config. Never stores credentials in output or manifest (ARTP-008), always dry-runs first (ARTP-002), halts and attempts rollback on failure (ARTP-009). Triggers when a release config has at least one enabled artifact handler."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Artifact Publisher
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Sub-protocol of ct-release-orchestrator. Runs the build-then-publish pipeline for every enabled artifact in `release.artifacts[]`: pre-validates the config, dry-runs each build, produces SHA-256 checksums, publishes sequentially, and delegates signing plus attestation to ct-provenance-keeper. Handles nine artifact types via a uniform handler interface.
|
|
11
|
+
|
|
12
|
+
## Core Principle
|
|
13
|
+
|
|
14
|
+
> Every artifact gets a checksum, a dry-run, and a rollback plan.
|
|
15
|
+
|
|
16
|
+
## Immutable Constraints
|
|
17
|
+
|
|
18
|
+
| ID | Rule | Enforcement |
|
|
19
|
+
|----|------|-------------|
|
|
20
|
+
| ARTP-001 | Artifact config MUST be validated before build. | `validate_artifact()` must return 0 before `build_artifact()` runs; exit 86. |
|
|
21
|
+
| ARTP-002 | Dry-run MUST execute before any real publish. | Pipeline halts if dry-run fails; exit 86. |
|
|
22
|
+
| ARTP-003 | Every handler MUST implement `{prefix}_validate`, `{prefix}_build`, `{prefix}_publish`. | Missing handler function exits 85. |
|
|
23
|
+
| ARTP-004 | SHA-256 checksums MUST be generated for every built artifact. | Missing checksum blocks publish. |
|
|
24
|
+
| ARTP-005 | Provenance metadata MUST be recorded via `record_release()` after publish. | Composition handoff to ct-provenance-keeper. |
|
|
25
|
+
| ARTP-006 | Multi-artifact publish MUST execute sequentially. | No parallel publishes; prevents race conditions. |
|
|
26
|
+
| ARTP-007 | Manifest entry MUST set `agent_type: "artifact-publish"`. | Validator rejects any other value. |
|
|
27
|
+
| ARTP-008 | Credentials MUST NOT appear in config, output, or manifest. | Agents declare env vars by name only; actual values stay in the environment. |
|
|
28
|
+
| ARTP-009 | Pipeline MUST halt and attempt rollback on the first publish failure. | Exit 88 on rollback success, exit 89 on rollback failure. |
|
|
29
|
+
|
|
30
|
+
## Supported Artifact Types
|
|
31
|
+
|
|
32
|
+
Nine registered handler types cover the common publishing surface. Each has a default build and publish command that the handler can override via config.
|
|
33
|
+
|
|
34
|
+
| Type | Build command (default) | Publish command (default) | Registry |
|
|
35
|
+
|------|-------------------------|---------------------------|----------|
|
|
36
|
+
| `npm-package` | (none, `npm publish` reads `files`) | `npm publish` | npmjs.org |
|
|
37
|
+
| `python-wheel` | `python -m build` | `twine upload dist/*` | pypi.org |
|
|
38
|
+
| `python-sdist` | `python -m build --sdist` | `twine upload dist/*` | pypi.org |
|
|
39
|
+
| `go-module` | `go mod tidy` | (tag push triggers proxy) | proxy.golang.org |
|
|
40
|
+
| `cargo-crate` | `cargo build --release` | `cargo publish` | crates.io |
|
|
41
|
+
| `ruby-gem` | `gem build *.gemspec` | `gem push *.gem` | rubygems.org |
|
|
42
|
+
| `docker-image` | `docker build -t <ref> .` | `docker push <ref>` | configurable (OCI) |
|
|
43
|
+
| `github-release` | (none) | `gh release create` | github.com |
|
|
44
|
+
| `generic-tarball` | `tar czf ...` | (custom) | configurable |
|
|
45
|
+
|
|
46
|
+
Per-type edge cases and exact invocation patterns live in [references/artifact-types.md](references/artifact-types.md).
|
|
47
|
+
|
|
48
|
+
## Handler Interface
|
|
49
|
+
|
|
50
|
+
Every handler is three Bash functions with a uniform contract:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Validate config, check tool availability, verify version consistency.
|
|
54
|
+
{prefix}_validate(artifact_config_json) -> exit 0 | 1
|
|
55
|
+
|
|
56
|
+
# Produce build output in a known location. Respects dry_run.
|
|
57
|
+
{prefix}_build(artifact_config_json, dry_run) -> exit 0 | 1
|
|
58
|
+
|
|
59
|
+
# Push build output to the registry. Respects dry_run.
|
|
60
|
+
{prefix}_publish(artifact_config_json, dry_run) -> exit 0 | 1
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
A full pseudocode example for a custom handler is in [references/handler-interface.md](references/handler-interface.md). To register a new handler:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
source lib/release-artifacts.sh
|
|
67
|
+
register_artifact_handler "my-custom-type" "my_custom"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Pipeline Phases
|
|
71
|
+
|
|
72
|
+
The sub-protocol runs in three ordered phases:
|
|
73
|
+
|
|
74
|
+
| Phase | Scope | Halt condition |
|
|
75
|
+
|-------|-------|----------------|
|
|
76
|
+
| 1. Pre-validate | All artifacts | Halt before any build |
|
|
77
|
+
| 2. Build | Sequential per artifact | Halt pipeline |
|
|
78
|
+
| 3. Publish | Sequential per artifact | Rollback published artifacts, then halt |
|
|
79
|
+
|
|
80
|
+
Sequential order matters: if artifact 1 (npm) publishes successfully but artifact 2 (docker) fails, the pipeline rolls back artifact 1 using `npm unpublish` (within 72 hours) before exiting. Rollback feasibility varies by registry — see composition.md in ct-release-orchestrator for the full table.
|
|
81
|
+
|
|
82
|
+
## Credentials Handling
|
|
83
|
+
|
|
84
|
+
Credentials are referenced, never stored. The skill reads environment variables by name from the config and verifies they are set before publishing:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"credentials": {
|
|
89
|
+
"envVar": "NPM_TOKEN",
|
|
90
|
+
"ciSecret": "NPM_TOKEN",
|
|
91
|
+
"required": true
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The skill MUST NOT:
|
|
97
|
+
|
|
98
|
+
- Echo or log credential values.
|
|
99
|
+
- Write credential values to `config.json` or the manifest entry.
|
|
100
|
+
- Pass credentials as CLI arguments (visible in `ps`).
|
|
101
|
+
- Include credential values in output files.
|
|
102
|
+
|
|
103
|
+
In CI, trusted publishing is preferred: the workflow exchanges an OIDC token for a short-lived registry credential, and the skill never sees the token. The CI path is already configured in `.github/workflows/release.yml` for npm.
|
|
104
|
+
|
|
105
|
+
Missing credentials exit 90 (`E_PROVENANCE_CONFIG_INVALID` bubbled from provenance) or fail the credential check with a clear error pointing at the missing env var.
|
|
106
|
+
|
|
107
|
+
## Integration
|
|
108
|
+
|
|
109
|
+
Validate the sub-protocol entry through `cleo check protocol`:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
cleo check protocol \
|
|
113
|
+
--protocolType artifact-publish \
|
|
114
|
+
--taskId T4901 \
|
|
115
|
+
--artifactType npm-package \
|
|
116
|
+
--buildPassed true
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Exit code 0 = artifact published successfully. Exit code 85 = unknown artifact type. Exit code 86 = validation failed. Exit code 87 = build failed. Exit code 88 = publish failed, rollback attempted. Exit code 89 = rollback failed, dirty state.
|
|
120
|
+
|
|
121
|
+
This skill always hands off to ct-provenance-keeper after publish, before writing the manifest entry, so the provenance chain is recorded in the same pipeline.
|
|
122
|
+
|
|
123
|
+
## Anti-Patterns
|
|
124
|
+
|
|
125
|
+
| Pattern | Problem | Solution |
|
|
126
|
+
|---------|---------|----------|
|
|
127
|
+
| Publishing without a dry-run first | Irreversible registry state on failure | ARTP-002 requires dry-run; the skill refuses to skip it |
|
|
128
|
+
| Storing credentials in `config.json` | Committed to VCS, visible to every agent | Reference by env var name; actual values stay in the environment |
|
|
129
|
+
| Parallel multi-artifact publish | Race conditions; partial state on failure | Sequential execution in config order (ARTP-006) |
|
|
130
|
+
| Skipping checksum generation | Cannot verify artifact integrity downstream | Generate SHA-256 for every build output |
|
|
131
|
+
| Logging credential values | Exposure in audit trail and agent context | Never echo credentials; test only the env var is set, not its value |
|
|
132
|
+
| Hardcoding registry URLs | Breaks across environments | Use the `registry` field in the config |
|
|
133
|
+
| Manual rollback without recording | Lost provenance chain | Record rollback in the manifest and the `releases.json` chain |
|
|
134
|
+
| Building before validating | Wastes time on invalid config | Pre-validate every artifact before the first build |
|
|
135
|
+
| Ignoring rollback failures | Leaves the pipeline in dirty state | Exit 89 and require manual intervention — do not retry blindly |
|
|
136
|
+
|
|
137
|
+
## Critical Rules Summary
|
|
138
|
+
|
|
139
|
+
1. Every artifact MUST be pre-validated before any build starts.
|
|
140
|
+
2. Every publish MUST be preceded by a successful dry-run.
|
|
141
|
+
3. Credentials MUST NEVER leave the environment — no logging, no config, no manifest.
|
|
142
|
+
4. Publishes run sequentially in config order; no parallel publishes.
|
|
143
|
+
5. SHA-256 checksums are mandatory for every build output.
|
|
144
|
+
6. Provenance MUST be recorded via `record_release()` after publish, via ct-provenance-keeper.
|
|
145
|
+
7. On first publish failure, halt and attempt rollback; exit 88 on clean rollback, 89 on dirty.
|
|
146
|
+
8. Validate every run via `cleo check protocol --protocolType artifact-publish`.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "CLEO-only metadata -- add to packages/skills/skills/manifest.json",
|
|
3
|
+
"name": "ct-artifact-publisher",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"tier": 2,
|
|
6
|
+
"token_budget": 8000,
|
|
7
|
+
"protocol": "artifact-publish",
|
|
8
|
+
"capabilities": {
|
|
9
|
+
"inputs": ["release-config", "version", "commit-sha"],
|
|
10
|
+
"outputs": ["built-artifacts", "checksums", "publish-results", "manifest-entry"],
|
|
11
|
+
"dispatch_triggers": [
|
|
12
|
+
"publish artifacts",
|
|
13
|
+
"build and publish",
|
|
14
|
+
"run artifact publish",
|
|
15
|
+
"ship packages",
|
|
16
|
+
"push to registry"
|
|
17
|
+
],
|
|
18
|
+
"compatible_subagent_types": ["general-purpose"],
|
|
19
|
+
"chains_to": ["ct-provenance-keeper"],
|
|
20
|
+
"dispatch_keywords": {
|
|
21
|
+
"primary": ["artifact", "publish", "registry", "package"],
|
|
22
|
+
"secondary": ["npm", "docker", "cargo", "tarball"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"constraints": {
|
|
26
|
+
"max_context_tokens": 60000,
|
|
27
|
+
"requires_session": false,
|
|
28
|
+
"requires_epic": false
|
|
29
|
+
}
|
|
30
|
+
}
|