Skip to content

Commit 0841059

Browse files
authored
Merge pull request #68 from ScriptKittyOS/chore/public-repo-posture
Separate the published tree from internal planning material; state the vulnerability response target and track the open dependency advisory; wait for the FIPS image instead of racing it; publish an OpenSSF Scorecard and check the workflows like code. Signed-off-by: Ayla Croft <aylacroft@proton.me>
2 parents 549cc6a + e799780 commit 0841059

198 files changed

Lines changed: 479 additions & 15125 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.credo.exs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
requires: [],
1212
checks: %{
1313
extra: [
14-
# CLAUDE.md §5: no runtime evaluation of model output. Covers the whole family,
14+
# docs/03-conventions.md, Engineering rules: no runtime evaluation of model output.
15+
# Covers the whole family,
1516
# because naming one function leaves an obvious bypass.
1617
{Trinity.Credo.NoEvalOnModelOutput, []}
1718
],

‎.githooks/commit-msg‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
# because a trailer that reaches a tag is permanent (CLAUDE.md §4).
77
#
88
# Enable with: git config core.hooksPath .githooks
9-
# Enforced by: scripts/plan_check.sh rule 8, which checks the history itself,
10-
# so a bypassed or unconfigured hook still fails the gate.
9+
# Enforced by: the gate's DCO check in CI, which reads the history itself, so a
10+
# bypassed or unconfigured hook still fails the build.
1111
set -eu
1212
msg_file="$1"
1313
tmp="$msg_file.stripped"
@@ -24,9 +24,8 @@ rm -f "$tmp"
2424
# Warning only: does every repo path the message names appear in the staged diff?
2525
#
2626
# Added at slice 001 G4, for a mistake this slice made three times: a commit whose message ran
27-
# ahead of its tree. Twice it was an unread `plan_check exit=1`; once a message and a NOTES
28-
# line said `src-tauri/Cargo.lock` had been added to REUSE.toml when the edit had failed on a
29-
# stale anchor, in the same output as a green gate. `mix gate` does not check that a commit
27+
# ahead of its tree: a message said `src-tauri/Cargo.lock` had been added to REUSE.toml
28+
# when the edit had failed on a stale anchor, in the same output as a green gate. `mix gate` does not check that a commit
3029
# message is true, and nothing else did either.
3130
#
3231
# **It warns and never blocks**, deliberately. A message legitimately names paths it does not

‎.github/dependabot.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#
44
# Dependabot opens a pull request only when a dependency has a security advisory. Version
55
# bumps are not raised: VERSIONS.md is the pin list, and a version lands only after it is
6-
# proposed in a slice's NOTES.md and approved (CLAUDE.md section 5). On its first run, with
6+
# proposed and reviewed, never adopted silently (docs/03-conventions.md). On its first run, with
77
# the limit above zero, it opened five version-bump pull requests inside two minutes; one of
88
# them was merged by mistake. An open-pull-requests-limit of 0 keeps the security updates and
99
# drops the rest. The value here is a security alert arriving as a diff with the gate run

‎.github/workflows/gate.yml‎

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,12 @@ jobs:
1515
steps:
1616
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
1717
with:
18-
fetch-depth: 0 # plan_check rule 8 reads the whole history
18+
fetch-depth: 0 # the DCO check below reads the whole history
1919
# On a pull request the default checkout is a merge commit GitHub makes on the fly,
20-
# authored by nobody and signed off by nobody. plan_check rule 8 refused it on the
21-
# first pull request this repository ever had (run 35477492177). The branch head is
22-
# what was written and signed, so that is what the gate reads. The ruleset's strict
23-
# policy requires the branch to be current with main before it can merge, so the
24-
# head is also what main will contain.
20+
# authored by nobody and signed off by nobody, which the DCO check below rightly
21+
# refuses. The branch head is what was written and signed, so that is what the gate
22+
# reads. The repository ruleset requires a branch to be current with main before it
23+
# can merge, so the head is also what main will contain.
2524
ref: ${{ github.event.pull_request.head.sha || github.sha }}
2625

2726
- uses: erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124 # v1.24.1
@@ -39,11 +38,7 @@ jobs:
3938

4039
- run: mix deps.get
4140

42-
# The plan's own consistency, checked before the code's.
43-
- run: ./scripts/plan_check.sh
44-
45-
# DCO. plan_check rule 8 also asserts every commit is signed off; this fails earlier
46-
# and more legibly on a pull request.
41+
# Developer Certificate of Origin: every commit carries a sign-off (ADR-0012).
4742
- name: DCO sign-off present on every commit
4843
run: |
4944
git log --format=%B ${{ github.event.pull_request.base.sha || 'HEAD~1' }}..HEAD 2>/dev/null \
@@ -120,6 +115,37 @@ jobs:
120115
- id: tag
121116
run: echo "ref=$(scripts/fips_image_tag.sh --ref)" >> "$GITHUB_OUTPUT"
122117

118+
# The image tag is a hash of the files that define the image, so any change to them -
119+
# including a comment - names an image that has to be built before it can be pulled. The
120+
# `fips` job below takes that image as its container, which GitHub pulls before the job's
121+
# first step runs, so the job cannot retry the pull itself: it fails with `manifest
122+
# unknown` and no output. The fips-image workflow builds and pushes on the same event, so
123+
# the two race, and the loser is always this one.
124+
#
125+
# Waiting here turns that race into a wait. The image is a function of its inputs, so the
126+
# one being waited for is exactly the one this commit needs, and a build from source is
127+
# slow enough that the ceiling is generous. A timeout fails with the reason rather than
128+
# with a pull error, because "the image is still building" and "the image will never
129+
# exist" need different responses from whoever reads it.
130+
- name: Wait for the FIPS image to be published
131+
env:
132+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
133+
run: |
134+
ref='${{ steps.tag.outputs.ref }}'
135+
echo "$GH_TOKEN" | docker login ghcr.io -u '${{ github.actor }}' --password-stdin
136+
for attempt in $(seq 1 60); do
137+
if docker manifest inspect "$ref" >/dev/null 2>&1; then
138+
echo "$ref is published (attempt $attempt)"
139+
exit 0
140+
fi
141+
echo "attempt $attempt: $ref is not published yet; waiting 30s"
142+
sleep 30
143+
done
144+
echo "::error::$ref was not published within 30 minutes. It is built by the" \
145+
"fips-image workflow, which runs when ci/fips/Containerfile, .tool-versions or" \
146+
"scripts/fips_image_tag.sh changes. Check that workflow's run for this commit."
147+
exit 1
148+
123149
fips:
124150
needs: fips-tag
125151
runs-on: ubuntu-latest
@@ -146,10 +172,9 @@ jobs:
146172
ref: ${{ github.event.pull_request.head.sha || github.sha }}
147173

148174
# The checkout action marks the workspace safe under a temporary HOME it removes when
149-
# it is done; every later git call in the container (plan_check, the names, secrets and
175+
# it is done; every later git call in the container (the names, secrets and
150176
# reuse censuses, all of which read `git ls-files`) then hits git's dubious-ownership
151-
# refusal and reads an empty tree. Found on run 35537462271: plan_check rule 4 named
152-
# every slice as missing its SLICE.md.
177+
# refusal and reads an empty tree, which makes every census pass over nothing.
153178
- run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
154179

155180
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
@@ -185,8 +210,6 @@ jobs:
185210
ERL_AFLAGS: "-eval application:load(crypto)"
186211
run: elixir scripts/crypto_supports.exs | diff - docs/fips-leg/supports-default.txt
187212

188-
- run: ./scripts/plan_check.sh
189-
190213
- name: DCO sign-off present on every commit
191214
run: |
192215
git log --format=%B ${{ github.event.pull_request.base.sha || 'HEAD~1' }}..HEAD 2>/dev/null \

‎.github/workflows/scorecard.yml‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# SPDX-FileCopyrightText: Sudo Apt Holdings LLC
2+
# SPDX-License-Identifier: Apache-2.0
3+
#
4+
# OpenSSF Scorecard. It measures this repository against the OpenSSF's own checks - branch
5+
# protection, pinned dependencies, signed releases, dangerous workflow patterns, token
6+
# permissions, maintenance and the rest - and publishes the result so that anyone evaluating the
7+
# project can read it without being asked to trust a claim made here.
8+
#
9+
# It runs weekly rather than on every push because the checks are about the repository's
10+
# configuration and history, which change slowly, and because the analysis reads the GitHub API
11+
# rather than the tree. The results are uploaded to the code-scanning dashboard, so a regression
12+
# in the repository's posture is visible in the same place as a code finding.
13+
name: scorecard
14+
15+
on:
16+
branch_protection_rule:
17+
schedule:
18+
# Mondays, 07:00 UTC. A fixed day makes a drop in the score attributable to the week it
19+
# appeared in rather than to an unknown point since the last look.
20+
- cron: '0 7 * * 1'
21+
push:
22+
branches: [main]
23+
24+
permissions: read-all
25+
26+
jobs:
27+
analysis:
28+
name: Scorecard analysis
29+
runs-on: ubuntu-latest
30+
permissions:
31+
# Upload the result to the code-scanning dashboard.
32+
security-events: write
33+
# Read the repository's own metadata (branch protection, releases, workflow runs).
34+
id-token: write
35+
contents: read
36+
actions: read
37+
38+
steps:
39+
- name: Checkout
40+
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
41+
with:
42+
persist-credentials: false
43+
44+
- name: Run analysis
45+
uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
46+
with:
47+
results_file: results.sarif
48+
results_format: sarif
49+
# Publishing makes the score readable at deps.dev and through the Scorecard API, which
50+
# is the point: an evaluator should be able to check the posture without asking us.
51+
publish_results: true
52+
53+
- name: Upload the result as an artifact
54+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
55+
with:
56+
name: scorecard-results
57+
path: results.sarif
58+
retention-days: 30
59+
60+
- name: Upload the result to code scanning
61+
uses: github/codeql-action/upload-sarif@416ff0dea110f80f0f56f0046500dbf7420e4bb0 # codeql-bundle-v2.27.1
62+
with:
63+
sarif_file: results.sarif

‎CHANGELOG.md‎

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<!-- SPDX-FileCopyrightText: Sudo Apt Holdings LLC -->
2+
<!-- SPDX-License-Identifier: Apache-2.0 -->
3+
# Changelog
4+
5+
Trinity is developed in reviewed units of work, each merged through a pull request with the
6+
quality gate green and then tagged. This file records what each tag delivered and how it was
7+
verified. It is derived from the tags themselves (`git tag -l 'slice/*'`), not written from
8+
memory.
9+
10+
The project is pre-alpha: there is no supported release series yet, and tags mark reviewed
11+
increments rather than supported versions. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
12+
loosely; versioning is by increment, and semantic versions begin at the first supported release.
13+
14+
Every entry below was gated on: formatting, a compile with warnings as errors, the architectural
15+
boundary check, Credo (strict), Sobelow, dependency and licence audits, the full test suite and a
16+
coverage floor. Entries from 2026-09-22 onward also required a release build check. Verification
17+
evidence for each increment is retained by the maintainers and summarised here.
18+
19+
## Unreleased
20+
21+
- Repository restructured for public review: internal planning material moved out of the published
22+
tree, engineering rules consolidated into `docs/03-conventions.md`, and this changelog added as
23+
the public record of delivered work.
24+
25+
## 2026-09-23
26+
27+
### `slice/070` — Gateway core
28+
Trinity becomes reachable from channels other than the desktop. An adapter behaviour carries text
29+
and nothing else; a router admits the sender, applies a rate limit, dispatches commands and binds
30+
the conversation to a session, streaming the reply back. An unknown sender receives a pairing code
31+
and nothing else: no session is created and no model is called until they are paired. Approvals
32+
raised during a channel-originated turn are rendered into that conversation, and what a channel may
33+
approve is capped below what the local desktop may, with the refusal recorded in the receipt chain.
34+
Ships an in-process console adapter; messaging platforms follow.
35+
36+
## 2026-09-22
37+
38+
### `slice/062` — MCP authorization
39+
OAuth 2.1 in every role for the Model Context Protocol surface: a resource server validating
40+
audience-bound tokens against an external authorization server, an optional personal-profile
41+
authorization server for a single operator's own machine, and a client role that obtains tokens
42+
from protected servers. Identity is separated from authority throughout: a token establishes who is
43+
calling, while the permission gate and the selected authority adapter decide whether an effect may
44+
happen. No token material reaches model context, logs or receipts.
45+
46+
### `slice/061` — MCP server
47+
Trinity serves the Model Context Protocol at revision 2026-07-28 over Streamable HTTP and stdio,
48+
with compatibility for 2025-11-25. Calls arriving over the protocol pass the same permission gate
49+
and effect membrane as local ones and leave the same receipts. A call requiring approval is held
50+
with sealed, tamper-evident state that the client retries once the operator has decided.
51+
52+
### `slice/050` — Scheduler
53+
Scheduled agent tasks on durable jobs, surviving restart, with cron or one-shot schedules, delivery
54+
targets, and a curator that marks stale records and archives untouched ones without deleting.
55+
56+
## 2026-09-21
57+
58+
### `slice/060` — MCP client
59+
A thin client driver: outbound requests are built here while decoding and validation use the
60+
protocol core's published functions. Every tool a server exposes becomes a namespaced tool that
61+
cannot borrow a built-in tool's permissions, every result is treated as untrusted content, and a
62+
server's mid-call question becomes an operator approval rather than an automatic answer.
63+
64+
### `slice/059` — MCP capability assessment
65+
A measured gap analysis of the protocol core against the 2026-07-28 checklist, and a probe of the
66+
extension seam the server side needs, recorded as findings rather than intentions.
67+
68+
### `slice/041` — Skill self-management
69+
Skills the system proposes for itself pass through staged approval and a scanner before becoming
70+
active.
71+
72+
### `slice/040` — Skills registry
73+
A registry for the open `SKILL.md` format with progressive disclosure of instructions.
74+
75+
### `slice/032` — Semantic memory
76+
Embeddings, semantic recall and hybrid retrieval, with a local model option and a vector store
77+
behind a behaviour.
78+
79+
## 2026-09-20
80+
81+
### `slice/034` — Export, import, restore
82+
The operator's data leaves in a documented archive format and comes back, with manifest validation.
83+
84+
### `slice/033` — Project context
85+
`AGENTS.md` from a session's project roots is loaded into context with precedence and a size cap.
86+
87+
### `slice/031` — Session search
88+
Full-text search over conversation history using SQLite FTS5.
89+
90+
### `slice/030` — Persona and always-on memory
91+
A persona document and a memory tier always present in context, scoped session, persona and global,
92+
with a budget and truncation recorded as evidence.
93+
94+
### `slice/024` — Effects, authority and receipts
95+
The effect catalog, authority selection at boot, and locally signed receipts. Authority is an
96+
adapter behind a behaviour: the shipped implementation decides locally, and a deployment may supply
97+
an external one, in which case this tree keeps no executor for the effects that adapter governs.
98+
Receipts are an Ed25519-signed hash chain with checkpoints and a verifier.
99+
100+
### `slice/023` — Context compaction
101+
Conversations that outgrow the window are compacted with lineage retained.
102+
103+
### `slice/022` — Core tools
104+
Filesystem, web fetch and search, and a shell tool, each behind the permission gate, with content
105+
from outside the machine marked untrusted.
106+
107+
### `slice/021` — Permission gate
108+
Every tool call is decided before it runs: allow once, for the session, or by a written rule, with
109+
the decision and its basis receipted. Approval surfaces carry no authority of their own.
110+
111+
### `slice/020` — Tool protocol and registry
112+
Tools are modules behind a behaviour plus a configuration entry; adding one requires no change to
113+
any core module, and the registry test asserts it.
114+
115+
### `slice/013` — Chat interface
116+
Streaming conversation in LiveView, with model output rendered through a single path.
117+
118+
### `slice/012` — Session process
119+
One supervised process per session, with crash recovery proven by killing the process.
120+
121+
### `slice/011` — Model provider layer
122+
Providers behind one behaviour, switched by configuration, with usage recorded per call.
123+
124+
### `slice/010` — Core domain and persistence
125+
The data model and repository layer, SQLite first with PostgreSQL supported, with gapless ordering
126+
under concurrent writers proven by a stress test.
127+
128+
### `slice/003` — FIPS build leg
129+
A continuous integration leg that builds from source and runs the cryptographic properties inside a
130+
FIPS-mode container, so claims about approved algorithms are measured rather than asserted.
131+
132+
## 2026-09-07
133+
134+
### `slice/001` — Packaging
135+
A self-contained desktop binary produced for Linux, macOS and Windows, each smoke-tested in CI.
136+
137+
## 2026-09-06
138+
139+
### `slice/000` — Toolchain and quality gate
140+
The repository, the pinned toolchain and the gate every later change has had to pass.

0 commit comments

Comments
 (0)