torve 0.1.0__py3-none-any.whl
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.
- torve/AGENTS.md +39 -0
- torve/__init__.py +10 -0
- torve/_migrations/AGENTS.md +12 -0
- torve/_migrations/substrate/FORZE_VERSION +1 -0
- torve/_migrations/substrate/postgres/0001_durable.sql +42 -0
- torve/_migrations/torve/postgres/0001_events.sql +40 -0
- torve/_migrations/torve/postgres/0002_decisions.sql +16 -0
- torve/_migrations/torve/postgres/README.md +4 -0
- torve/_skills/AGENTS.md +50 -0
- torve/_skills/corpus-bootstrap/AGENTS.md +3 -0
- torve/_skills/corpus-bootstrap/SKILL.md +128 -0
- torve/_skills/corpus-bootstrap/fixtures/S-0001/decisions.yaml +45 -0
- torve/_skills/corpus-bootstrap/fixtures/S-0001/document.yaml +56 -0
- torve/_skills/corpus-bootstrap/fixtures/survey-report.json +359 -0
- torve/_skills/corpus-bootstrap/references/doctrine.md +85 -0
- torve/_skills/corpus-bootstrap/references/draft-template.md +74 -0
- torve/_skills/corpus-bootstrap/references/workflow.md +93 -0
- torve/_skills/flag-dont-flip/SKILL.md +166 -0
- torve/_skills/ratchet-what-you-build/SKILL.md +66 -0
- torve/_skills/ratchet-what-you-build/references/the-ladder.md +29 -0
- torve/_skills/spec-writer/AGENTS.md +13 -0
- torve/_skills/spec-writer/SKILL.md +191 -0
- torve/_skills/spec-writer/references/authoring.md +59 -0
- torve/_skills/spec-writer/references/spec-template.md +161 -0
- torve/_skills/spec-writer/references/workflows.md +178 -0
- torve/_skills/working-rules/AGENTS.md +54 -0
- torve/_skills/working-rules/SKILL.md +137 -0
- torve/_web/AGENTS.md +12 -0
- torve/_web/assets/index-KQVC6uXc.css +1 -0
- torve/_web/assets/index-Nc9hy-rB.js +70 -0
- torve/_web/index.html +15 -0
- torve/adapters/AGENTS.md +21 -0
- torve/adapters/__init__.py +2 -0
- torve/adapters/agent/AGENTS.md +212 -0
- torve/adapters/agent/__init__.py +0 -0
- torve/adapters/agent/fake.py +117 -0
- torve/adapters/agent/harness.py +1971 -0
- torve/adapters/broker/AGENTS.md +13 -0
- torve/adapters/broker/__init__.py +36 -0
- torve/adapters/broker/local.py +956 -0
- torve/adapters/broker/none.py +57 -0
- torve/adapters/eventstore/__init__.py +0 -0
- torve/adapters/eventstore/document.py +73 -0
- torve/adapters/notify/AGENTS.md +3 -0
- torve/adapters/notify/__init__.py +12 -0
- torve/adapters/notify/inert.py +26 -0
- torve/adapters/notify/webhook.py +106 -0
- torve/adapters/runtime/AGENTS.md +42 -0
- torve/adapters/runtime/__init__.py +0 -0
- torve/adapters/runtime/docker.py +357 -0
- torve/adapters/runtime/opensandbox.py +439 -0
- torve/adapters/store/__init__.py +0 -0
- torve/adapters/store/durable.py +70 -0
- torve/adapters/vcs/AGENTS.md +62 -0
- torve/adapters/vcs/__init__.py +0 -0
- torve/adapters/vcs/git.py +1200 -0
- torve/adapters/workspace/AGENTS.md +27 -0
- torve/adapters/workspace/__init__.py +0 -0
- torve/adapters/workspace/git.py +377 -0
- torve/application/AGENTS.md +1648 -0
- torve/application/__init__.py +1 -0
- torve/application/channel.py +152 -0
- torve/application/colocation.py +475 -0
- torve/application/contextpack.py +844 -0
- torve/application/decisions.py +989 -0
- torve/application/dispatch.py +710 -0
- torve/application/divergence.py +571 -0
- torve/application/enginelock.py +74 -0
- torve/application/equipment.py +418 -0
- torve/application/evals.py +626 -0
- torve/application/eventlog.py +415 -0
- torve/application/executors.py +143 -0
- torve/application/feedback.py +126 -0
- torve/application/fleet.py +256 -0
- torve/application/forge.py +436 -0
- torve/application/intake.py +2057 -0
- torve/application/lane.py +1982 -0
- torve/application/ledger.py +683 -0
- torve/application/manager.py +767 -0
- torve/application/migrate.py +224 -0
- torve/application/notify.py +268 -0
- torve/application/planner.py +1135 -0
- torve/application/ports.py +660 -0
- torve/application/projections.py +2158 -0
- torve/application/reaper.py +514 -0
- torve/application/residency.py +952 -0
- torve/application/review.py +1283 -0
- torve/application/reviewleg.py +1250 -0
- torve/application/runner.py +1501 -0
- torve/application/runstate.py +226 -0
- torve/application/session.py +942 -0
- torve/application/shadow.py +184 -0
- torve/application/sizing.py +107 -0
- torve/application/skills.py +91 -0
- torve/application/specquality.py +928 -0
- torve/application/standing.py +665 -0
- torve/application/survey.py +230 -0
- torve/application/taskstore.py +167 -0
- torve/application/telemetry.py +1302 -0
- torve/application/threads.py +107 -0
- torve/application/worker.py +239 -0
- torve/base/AGENTS.md +28 -0
- torve/base/__init__.py +1 -0
- torve/base/clock.py +49 -0
- torve/base/model.py +14 -0
- torve/base/naming.py +151 -0
- torve/base/shell.py +149 -0
- torve/cli/AGENTS.md +568 -0
- torve/cli/__init__.py +9 -0
- torve/cli/__main__.py +7 -0
- torve/cli/assembly.py +231 -0
- torve/cli/brief.py +183 -0
- torve/cli/console.py +295 -0
- torve/cli/context.py +458 -0
- torve/cli/decisions.py +440 -0
- torve/cli/doctor.py +988 -0
- torve/cli/equip.py +184 -0
- torve/cli/evals.py +559 -0
- torve/cli/feedback.py +54 -0
- torve/cli/fleet.py +215 -0
- torve/cli/gates.py +288 -0
- torve/cli/init.py +291 -0
- torve/cli/intake.py +350 -0
- torve/cli/ledger.py +327 -0
- torve/cli/log.py +469 -0
- torve/cli/main.py +164 -0
- torve/cli/manager.py +1104 -0
- torve/cli/mcp.py +179 -0
- torve/cli/merge.py +438 -0
- torve/cli/migrate.py +87 -0
- torve/cli/night.py +244 -0
- torve/cli/options.py +285 -0
- torve/cli/plan.py +403 -0
- torve/cli/review.py +744 -0
- torve/cli/run.py +404 -0
- torve/cli/sandbox.py +311 -0
- torve/cli/serve.py +275 -0
- torve/cli/shadow.py +205 -0
- torve/cli/sources.py +245 -0
- torve/cli/spec.py +1664 -0
- torve/cli/status.py +248 -0
- torve/cli/survey.py +245 -0
- torve/cli/why.py +276 -0
- torve/config/AGENTS.md +638 -0
- torve/config/__init__.py +1 -0
- torve/config/agents.py +713 -0
- torve/config/equipment.py +165 -0
- torve/config/fleet.py +187 -0
- torve/config/layout.py +116 -0
- torve/config/manifest.py +341 -0
- torve/config/providers.py +374 -0
- torve/config/runconfig.py +2025 -0
- torve/config/sources.py +222 -0
- torve/config/spec.py +1474 -0
- torve/config/spec_emit.py +692 -0
- torve/domain/AGENTS.md +317 -0
- torve/domain/__init__.py +1 -0
- torve/domain/attempt.py +87 -0
- torve/domain/events.py +701 -0
- torve/domain/source.py +111 -0
- torve/domain/spec.py +769 -0
- torve/domain/states.py +148 -0
- torve/domain/task.py +232 -0
- torve/domain/vocabulary.py +82 -0
- torve/gates/AGENTS.md +269 -0
- torve/gates/__init__.py +37 -0
- torve/gates/acceptance.py +190 -0
- torve/gates/context.py +309 -0
- torve/gates/contract.py +41 -0
- torve/gates/decisions_reported.py +487 -0
- torve/gates/evidence.py +100 -0
- torve/gates/no_test_tampering.py +52 -0
- torve/gates/red_on_base.py +198 -0
- torve/gates/runner.py +318 -0
- torve/gates/sabotage.py +747 -0
- torve/gates/scope.py +89 -0
- torve/gates/secrets.py +111 -0
- torve/gates/self_audit.py +44 -0
- torve/gates/source_layout.py +58 -0
- torve/gates/user_facing_text.py +157 -0
- torve/py.typed +0 -0
- torve-0.1.0.dist-info/METADATA +257 -0
- torve-0.1.0.dist-info/RECORD +186 -0
- torve-0.1.0.dist-info/WHEEL +4 -0
- torve-0.1.0.dist-info/entry_points.txt +2 -0
- torve-0.1.0.dist-info/licenses/LICENSE +21 -0
torve/AGENTS.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!-- torve:managed src/torve — rendered from the corpus; do not edit by hand -->
|
|
2
|
+
|
|
3
|
+
## Decisions governing `src/torve/`
|
|
4
|
+
|
|
5
|
+
### S-0055/D-23 — `LOCKED` (Standing decisions)
|
|
6
|
+
|
|
7
|
+
Five layers — `base`, `domain`, `application`, `adapters`, `cli`, beside `gates` and `config` — with import directions enforced by import-linter over the whole package; the `layering` gate blocks
|
|
8
|
+
|
|
9
|
+
- Paths: `src/torve/**` `pyproject.toml`
|
|
10
|
+
- Consequence: The hexagon is visible in the tree and mechanically held
|
|
11
|
+
- Touching these paths owes a divergence entry: `torve log owed <task> --touched <files>` before you finish
|
|
12
|
+
|
|
13
|
+
### S-0055/D-27 — `ASSUMED` (Standing decisions)
|
|
14
|
+
|
|
15
|
+
No module is named `models`, `utils`, `helpers`, `common` or `base` below the package root; modules are named for what they hold, and the `source-layout` gate reads it
|
|
16
|
+
|
|
17
|
+
- Paths: `src/torve/**`
|
|
18
|
+
- Consequence: Names that admit anything accumulate everything
|
|
19
|
+
|
|
20
|
+
### S-0055/D-59 — `ASSUMED` (Standing decisions)
|
|
21
|
+
|
|
22
|
+
Strict typing is a floor over `src/`: `mypy --strict` and `basedpyright` strict block CI and the acceptance fallback; tests, scripts and skills carry no type floor
|
|
23
|
+
|
|
24
|
+
- Paths: `src/torve/**` `pyproject.toml`
|
|
25
|
+
- Consequence: A substrate surface change fails at the type check
|
|
26
|
+
|
|
27
|
+
## Invariants holding over `src/torve/`
|
|
28
|
+
|
|
29
|
+
- **S-0055/I-1**: The five layer contracts hold over the whole package
|
|
30
|
+
- Paths: `src/torve/**` `pyproject.toml`
|
|
31
|
+
- Check: `uv run lint-imports --config pyproject.toml`
|
|
32
|
+
- **S-0055/I-4**: The typing floor over src holds
|
|
33
|
+
- Paths: `src/torve/**`
|
|
34
|
+
- Check: `uv run mypy src && uv run basedpyright src`
|
|
35
|
+
- **S-0055/I-5**: The suite is green
|
|
36
|
+
- Paths: `src/torve/**` `tests/**`
|
|
37
|
+
- Check: `uv run pytest`
|
|
38
|
+
|
|
39
|
+
<!-- /torve:managed -->
|
torve/__init__.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Torve — deterministic gates for agent and human pull requests.
|
|
2
|
+
|
|
3
|
+
Names resolve from their canonical modules: `torve.gates.runner.run_gates`,
|
|
4
|
+
`torve.domain.task.Task`, and so on. There is no re-export table — the
|
|
5
|
+
gates-only CI path never imports the runner, the store or an adapter because
|
|
6
|
+
nothing here imports them, not because a lazy front door defers them
|
|
7
|
+
(S-0015/the-front-door, S-0015/A-2).
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!-- torve:managed migrations — rendered from the corpus; do not edit by hand -->
|
|
2
|
+
|
|
3
|
+
## Decisions governing `migrations/`
|
|
4
|
+
|
|
5
|
+
### S-0055/D-43 — `ASSUMED` (Standing decisions)
|
|
6
|
+
|
|
7
|
+
Migrations are owner-grouped, forward-only SQL under `migrations/`; the substrate is pinned by `FORZE_VERSION`, which `torve doctor` enforces and `config_hash` digests
|
|
8
|
+
|
|
9
|
+
- Paths: `migrations/**` `src/torve/application/migrate.py` `src/torve/cli/doctor.py`
|
|
10
|
+
- Consequence: A substrate surface change fails at the pin bump, not in production
|
|
11
|
+
|
|
12
|
+
<!-- /torve:managed -->
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.10.0
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
-- Substrate: durable run store + step journal (forze, schema per the
|
|
2
|
+
-- adapter docstrings of PostgresDurableRunStore / the step adapter).
|
|
3
|
+
-- Owner: substrate — this file changes when forze is upgraded, never for
|
|
4
|
+
-- torve's own reasons (S-0012/D-1). Forward-only (S-0012/D-4).
|
|
5
|
+
--
|
|
6
|
+
-- Do not trim columns: every read projects cancel_requested_at /
|
|
7
|
+
-- cancel_refused_at, and a missing column makes lease renewal raise, which a
|
|
8
|
+
-- heartbeat reads as lease lost.
|
|
9
|
+
|
|
10
|
+
CREATE TABLE IF NOT EXISTS public.torve_durable_run (
|
|
11
|
+
run_id text NOT NULL,
|
|
12
|
+
name text NOT NULL,
|
|
13
|
+
status text NOT NULL,
|
|
14
|
+
idempotency_key text,
|
|
15
|
+
input jsonb,
|
|
16
|
+
output jsonb,
|
|
17
|
+
error text,
|
|
18
|
+
tenant_id uuid,
|
|
19
|
+
attempts integer NOT NULL DEFAULT 0,
|
|
20
|
+
leased_until timestamptz,
|
|
21
|
+
available_at timestamptz,
|
|
22
|
+
created_at timestamptz NOT NULL,
|
|
23
|
+
updated_at timestamptz NOT NULL,
|
|
24
|
+
cancel_requested_at timestamptz,
|
|
25
|
+
cancel_refused_at timestamptz,
|
|
26
|
+
PRIMARY KEY (run_id),
|
|
27
|
+
UNIQUE (idempotency_key)
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
CREATE INDEX IF NOT EXISTS torve_durable_run_status_created
|
|
31
|
+
ON public.torve_durable_run (status, created_at);
|
|
32
|
+
CREATE INDEX IF NOT EXISTS torve_durable_run_created_desc
|
|
33
|
+
ON public.torve_durable_run (created_at DESC, run_id DESC);
|
|
34
|
+
|
|
35
|
+
CREATE TABLE IF NOT EXISTS public.torve_durable_step (
|
|
36
|
+
run_id text NOT NULL,
|
|
37
|
+
step_id text NOT NULL,
|
|
38
|
+
result jsonb NOT NULL,
|
|
39
|
+
tenant_id uuid,
|
|
40
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
41
|
+
PRIMARY KEY (run_id, step_id)
|
|
42
|
+
);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
-- Torve: the event log (S-0044/the-event-log). Owner: torve — this file changes for
|
|
2
|
+
-- torve's own reasons, never for a forze upgrade (S-0012/D-1). Forward-only
|
|
3
|
+
-- (S-0012/D-4).
|
|
4
|
+
--
|
|
5
|
+
-- The relation backs the `torve-events` document spec, so every column name
|
|
6
|
+
-- is a field name on the aggregate's models and the two must move together;
|
|
7
|
+
-- `id`, `rev`, `created_at` and `last_update_at` come from the document base
|
|
8
|
+
-- rather than from anything torve declared.
|
|
9
|
+
--
|
|
10
|
+
-- Append-only is a property of the spec above this table — it declares no
|
|
11
|
+
-- update command, so the adapter exposes no update port — and `rev` is here
|
|
12
|
+
-- because the document base carries it, not because a row is ever revised.
|
|
13
|
+
-- A correction is another event.
|
|
14
|
+
|
|
15
|
+
CREATE TABLE IF NOT EXISTS public.torve_event (
|
|
16
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
17
|
+
rev integer NOT NULL DEFAULT 1,
|
|
18
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
19
|
+
last_update_at timestamptz NOT NULL DEFAULT now(),
|
|
20
|
+
schema_version integer NOT NULL DEFAULT 1,
|
|
21
|
+
kind text NOT NULL,
|
|
22
|
+
partition text NOT NULL,
|
|
23
|
+
subject_type text NOT NULL,
|
|
24
|
+
subject_id text NOT NULL,
|
|
25
|
+
actor_kind text NOT NULL,
|
|
26
|
+
actor_id text NOT NULL,
|
|
27
|
+
payload jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
28
|
+
correlation_id text,
|
|
29
|
+
causation_id text
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
-- The log's two reads (S-0044/ports-and-what-binds-first): one subject's history, and one
|
|
33
|
+
-- partition's tail. Both order by (created_at, id) — the timestamp is not a
|
|
34
|
+
-- total order under concurrency and the id is the stable tiebreak, so the
|
|
35
|
+
-- index carries both or the sort spills.
|
|
36
|
+
CREATE INDEX IF NOT EXISTS torve_event_subject
|
|
37
|
+
ON public.torve_event (subject_id, created_at, id);
|
|
38
|
+
|
|
39
|
+
CREATE INDEX IF NOT EXISTS torve_event_partition
|
|
40
|
+
ON public.torve_event (partition, created_at, id);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-- Torve: the decision graph's read (S-0047/the-read-that-does-not-fold-an-execution-log, S-0047/D-7). Owner: torve —
|
|
2
|
+
-- this file changes for torve's own reasons, never for a forze upgrade
|
|
3
|
+
-- (S-0012/D-1). Forward-only (S-0012/D-4).
|
|
4
|
+
--
|
|
5
|
+
-- Sources and decisions grow with the corpus; attempts, gates and burn grow
|
|
6
|
+
-- with execution. `torve_event_partition` serves the board, which wants a
|
|
7
|
+
-- partition's whole tail; this one serves the decision graph, which wants
|
|
8
|
+
-- the corpus-sized slice of it and would otherwise fold an execution log to
|
|
9
|
+
-- find a few hundred rows.
|
|
10
|
+
--
|
|
11
|
+
-- Ordered by (created_at, id) for the same reason 0001 is: the timestamp is
|
|
12
|
+
-- not a total order under concurrency and the id is the stable tiebreak, so
|
|
13
|
+
-- the index carries both or the sort spills.
|
|
14
|
+
|
|
15
|
+
CREATE INDEX IF NOT EXISTS torve_event_subject_type
|
|
16
|
+
ON public.torve_event (partition, subject_type, created_at, id);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
# Torve document tables (tasks_ref, attempts, gate_results, findings,
|
|
2
|
+
# review_feedback) arrive with the attempts store; this history starts at the
|
|
3
|
+
# first table. Creating the directory early keeps `torve migrate torve` a
|
|
4
|
+
# stable no-op rather than an unknown target (S-0012/D-6).
|
torve/_skills/AGENTS.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<!-- torve:managed skills — rendered from the corpus; do not edit by hand -->
|
|
2
|
+
|
|
3
|
+
## Decisions governing `skills/`
|
|
4
|
+
|
|
5
|
+
### S-0055/D-36 — `ASSUMED` (Standing decisions)
|
|
6
|
+
|
|
7
|
+
Skills ship as package data under `skills/` and are materialised role-scoped into the sandbox; a vendored skill lives under `.torve/skills-vendor/`; a name in both refuses, a name in neither is a configuration error
|
|
8
|
+
|
|
9
|
+
- Paths: `skills/**` `.torve/skills-vendor/**` `src/torve/application/skills.py`
|
|
10
|
+
- Consequence: What an agent knows is versioned and named, never ambient
|
|
11
|
+
|
|
12
|
+
### S-0056/D-8 — `ASSUMED` (Structure for everything) — implementation: none
|
|
13
|
+
|
|
14
|
+
`SKILL.md`, `AGENTS.md`, the colocated sections and the pack are unchanged: projections rendered from the model, read by harnesses and people
|
|
15
|
+
|
|
16
|
+
- Paths: `skills/**` `src/torve/application/colocation.py`
|
|
17
|
+
- Consequence: Nothing a harness reads changes shape
|
|
18
|
+
|
|
19
|
+
### S-0057/D-4 — `LOCKED` (The specification is a directory)
|
|
20
|
+
|
|
21
|
+
`torve spec` absorbs every `torve rfc` verb and `cli/rfc.py` is deleted; the gate is `spec-valid`; the skill is `spec-writer`; `rfc_emit.py` becomes `spec_emit.py`; new prose says specification or document
|
|
22
|
+
|
|
23
|
+
- Paths: `src/torve/cli/spec.py` `src/torve/cli/spec.py` `src/torve/config/spec_emit.py` `skills/**` `.torve/gates.yaml`
|
|
24
|
+
- Consequence: One namespace for the corpus; old prose and test file names keep the old word
|
|
25
|
+
- Touching these paths owes a divergence entry: `torve log owed <task> --touched <files>` before you finish
|
|
26
|
+
|
|
27
|
+
### S-0058/D-2 — `LOCKED` (One grammar and the anatomy)
|
|
28
|
+
|
|
29
|
+
Every existing identifier converts once through a mapping committed as `.torve/archive/identifiers.yaml`, applied to the corpus, the archive, `src/`, `pages/`, `skills/`, the README, the local task files and the projections, with "RFC NNNN §n" converted to the section key at that position; a parity script gates the commit and is not committed
|
|
30
|
+
|
|
31
|
+
- Paths: `.torve/specs/**` `.torve/archive/**` `src/**` `pages/**` `skills/**` `README.md`
|
|
32
|
+
- Consequence: No legacy identifier stands anywhere the check reads; history keeps its words and resolves through the mapping
|
|
33
|
+
- Touching these paths owes a divergence entry: `torve log owed <task> --touched <files>` before you finish
|
|
34
|
+
|
|
35
|
+
### S-0058/D-10 — `ASSUMED` (One grammar and the anatomy)
|
|
36
|
+
|
|
37
|
+
The skill and its template, the schemas `torve init` writes, the projections beside the code and the operating page follow the grammar and the anatomy in the same phase that changes them
|
|
38
|
+
|
|
39
|
+
- Paths: `skills/**` `src/torve/application/colocation.py` `src/torve/cli/init.py` `pages/docs/operating.md`
|
|
40
|
+
- Consequence: Nothing a harness or a person reads names an identifier the check refuses
|
|
41
|
+
|
|
42
|
+
### S-0062/D-6 — `LOCKED` (Equipment is declared, and the harness is told how to take it)
|
|
43
|
+
|
|
44
|
+
A skill a gate reads stays package data, versioned with the engine; `torve:` is the source that names one.
|
|
45
|
+
|
|
46
|
+
- Paths: `src/torve/application/skills.py` `skills/**`
|
|
47
|
+
- Consequence: the two skills this engine ships cannot drift against the gate that parses what they teach
|
|
48
|
+
- Touching these paths owes a divergence entry: `torve log owed <task> --touched <files>` before you finish
|
|
49
|
+
|
|
50
|
+
<!-- /torve:managed -->
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: corpus-bootstrap
|
|
3
|
+
description: Drafting a brownfield adopter's standing-decisions baseline from the survey report — mostly ASSUMED, LOCKED only on defended boundaries, paths on every row, no phasing, one draft document for a human to edit, commit and accept.
|
|
4
|
+
roles: [author]
|
|
5
|
+
gate: spec-valid
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
> **Specialisation.** Derived from `agent-skills/corpus-bootstrap`, specialised for
|
|
9
|
+
> artefacts that Torve parses. Divergence from upstream is expected and
|
|
10
|
+
> intentional — **do not reconcile**. Improvements of general value flow
|
|
11
|
+
> upstream, not the reverse.
|
|
12
|
+
|
|
13
|
+
# Corpus Bootstrap — the baseline draft
|
|
14
|
+
|
|
15
|
+
This skill is the second half of first contact with a repository that has no
|
|
16
|
+
corpus. The engine's `torve survey` did the first half: it replayed the last
|
|
17
|
+
landings through the gate battery and produced a read-only report of what
|
|
18
|
+
would have fired and what stayed silent for want of a corpus. This skill —
|
|
19
|
+
run in a supervised session, **never by the engine** — reads that report and
|
|
20
|
+
the repository, and drafts the standing-decisions document that turns the
|
|
21
|
+
report's silence into governance.
|
|
22
|
+
|
|
23
|
+
The engine never reads this skill's output while it is a draft. It only ever
|
|
24
|
+
reads the committed, human-accepted document, through the standing
|
|
25
|
+
inheritance layer: from acceptance, every row whose declared paths intersect
|
|
26
|
+
a contract's scope rides into that contract at mint time, and nothing else
|
|
27
|
+
(S-0031/D-2). There is no engine surface for the baseline at all — which is the
|
|
28
|
+
point: a skill can be supervised, edited and refused in a diff; an engine
|
|
29
|
+
surface would drift.
|
|
30
|
+
|
|
31
|
+
## Inputs and output
|
|
32
|
+
|
|
33
|
+
- **Input:** the survey report (the JSON `torve survey --format json`
|
|
34
|
+
writes) and the repository working tree. The report is the evidence base;
|
|
35
|
+
the tree is where the boundaries live and where their globs are read from.
|
|
36
|
+
- **Output:** one draft document in this corpus's format — frontmatter, an
|
|
37
|
+
H1, a Decisions section holding the decision table, no Phasing section —
|
|
38
|
+
written so a human can edit, commit and accept it in one review. The draft
|
|
39
|
+
is `status: draft`; acceptance is the human flipping it to `accepted` in
|
|
40
|
+
the same commit that signs it.
|
|
41
|
+
|
|
42
|
+
## The extraction doctrine
|
|
43
|
+
|
|
44
|
+
Four rules, in order of how much damage breaking them does:
|
|
45
|
+
|
|
46
|
+
1. **Mostly ASSUMED.** A grade is a human judgement about reversal cost, and
|
|
47
|
+
a stranger's repository has no corpus — nobody has made that judgement.
|
|
48
|
+
Default every candidate row to `ASSUMED` and let the human's acceptance
|
|
49
|
+
edits do the real grading. An extraction that comes back mostly `LOCKED`
|
|
50
|
+
poisons the entry: the acceptance review reads it as a takeover and
|
|
51
|
+
refuses the whole document.
|
|
52
|
+
|
|
53
|
+
2. **LOCKED only on defended boundaries.** A `LOCKED` row claims reopening is
|
|
54
|
+
expensive. The only evidence an extraction can cite for that is the
|
|
55
|
+
repository's own history showing the boundary being **defended**: a
|
|
56
|
+
firing followed by a correction landing, or a consistent clean record
|
|
57
|
+
with the boundary visible in the tree (the layout is deliberate because
|
|
58
|
+
the history holds it). A single firing in a short window is
|
|
59
|
+
`ASSUMED`-grade evidence — the boundary exists as a check, but nobody has
|
|
60
|
+
been shown defending it.
|
|
61
|
+
|
|
62
|
+
3. **Paths on every row.** A row without declared paths is never standing —
|
|
63
|
+
the inheritance layer skips it and the row governs nothing. Every row
|
|
64
|
+
names the globs it governs, read from the actual tree, not invented.
|
|
65
|
+
|
|
66
|
+
4. **No phasing.** The baseline is a set of standing rows, not work to
|
|
67
|
+
sequence. A Phasing section would make the engine mint tasks from a
|
|
68
|
+
baseline document — exactly the engine surface S-0031/D-2 refuses. The
|
|
69
|
+
baseline answers "how is this repository governed"; sequencing is another
|
|
70
|
+
document's job, and the draft has no `## Phasing` section.
|
|
71
|
+
|
|
72
|
+
## Reading the survey
|
|
73
|
+
|
|
74
|
+
The report is the evidence base; read it before the tree.
|
|
75
|
+
|
|
76
|
+
- **Fired** (`outcome` in `fail`/`error`/`bypassed`) — a boundary was
|
|
77
|
+
crossed in history. Name the landing, then go to the tree: was the
|
|
78
|
+
crossing corrected later? That correction is the defended-boundary
|
|
79
|
+
evidence rule 2 wants.
|
|
80
|
+
- **Clean** (`pass`/`flaky`) — measured nothing wrong. No row follows from a
|
|
81
|
+
clean gate alone; the boundary it measures is already being held.
|
|
82
|
+
- **Skipped with `no_corpus: true`** — the gate did not run because no task
|
|
83
|
+
contract existed: the corpus's absence made visible. These are the rows
|
|
84
|
+
the baseline exists to write: a standing row that gives the gate
|
|
85
|
+
something to measure once work is minted.
|
|
86
|
+
- **Skipped with `no_corpus: false`** — the runner's fail-fast "not run"
|
|
87
|
+
after an earlier blocking gate fired, or acceptance's structural no-commands
|
|
88
|
+
skip. Not a corpus gap; no row follows.
|
|
89
|
+
- **The summary's `corpus_adds`** — the gates that never measured a single
|
|
90
|
+
landing and whose silence is the no-task skip. The report already names
|
|
91
|
+
them; every one of them becomes a candidate `ASSUMED` row.
|
|
92
|
+
|
|
93
|
+
## The shape this skill records (S-0031/D-6)
|
|
94
|
+
|
|
95
|
+
The baseline is **one document per adoption**, named
|
|
96
|
+
the `S-NNNN/` directory in the corpus path (`.torve/specs/` by default),
|
|
97
|
+
with `NNNN` the next free corpus number and the title "Standing decisions".
|
|
98
|
+
Rationale: a first adopter has no areas taxonomy to split by, a single
|
|
99
|
+
document keeps the acceptance ceremony to one commit, and the inheritance
|
|
100
|
+
layer already selects rows by path intersection — several-by-area buys
|
|
101
|
+
nothing until a corpus has enough rows to need it. The first real adoption
|
|
102
|
+
settles this shape; this paragraph is the skill recording the shape it
|
|
103
|
+
chose, and the recording is updated to what the adoption chose.
|
|
104
|
+
|
|
105
|
+
## The hand-off
|
|
106
|
+
|
|
107
|
+
The extraction produces a **draft**. The human then:
|
|
108
|
+
|
|
109
|
+
1. Edits — grading, wording, the paths, anything the history suggests.
|
|
110
|
+
2. Commits — the draft becomes a committed document.
|
|
111
|
+
3. Accepts — `status: accepted`, the commit that makes the rows stand.
|
|
112
|
+
|
|
113
|
+
Nothing the engine reads exists before that commit, and nothing the engine
|
|
114
|
+
reads after it is this skill's doing: standing inheritance copies grade and
|
|
115
|
+
paths at mint time and the battery convicts only work minted after — a
|
|
116
|
+
ratchet, never a purge (S-0031/D-3).
|
|
117
|
+
|
|
118
|
+
## References
|
|
119
|
+
|
|
120
|
+
- `references/doctrine.md` — the extraction doctrine in detail: grading
|
|
121
|
+
evidence, path discipline, what the survey's four outcomes mean
|
|
122
|
+
- `references/workflow.md` — the supervised-session procedure, inputs to
|
|
123
|
+
accepted document
|
|
124
|
+
- `references/draft-template.md` — the corpus-format skeleton the draft is
|
|
125
|
+
written from
|
|
126
|
+
- `fixtures/survey-report.json` — a sample survey report (input)
|
|
127
|
+
- `fixtures/S-0001/` — the checkable output shape: the draft
|
|
128
|
+
the doctrine produces from the sample report
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../../schemas/decisions.json
|
|
2
|
+
decisions:
|
|
3
|
+
- id: D-1
|
|
4
|
+
grade: LOCKED
|
|
5
|
+
text: >-
|
|
6
|
+
Credentials never enter the source tree; secrets are injected from the deployment
|
|
7
|
+
environment
|
|
8
|
+
paths: [src/**, .env.example]
|
|
9
|
+
consequence: >-
|
|
10
|
+
The repository's history defended this boundary: the survey's secrets gate fired
|
|
11
|
+
when a key landed in `src/leak.py` and the next landing removed it; crossing
|
|
12
|
+
it again is expensive to undo
|
|
13
|
+
- id: D-2
|
|
14
|
+
grade: ASSUMED
|
|
15
|
+
text: >-
|
|
16
|
+
Product code lives under `src/**`; operational scripts live under `scripts/**`
|
|
17
|
+
paths: [src/**, scripts/**]
|
|
18
|
+
consequence: >-
|
|
19
|
+
The survey's scope gate fired once on a root-level deploy script and stayed
|
|
20
|
+
clean on the other four landings; whether the layout is deliberate is the acceptance
|
|
21
|
+
edit's call
|
|
22
|
+
- id: D-3
|
|
23
|
+
grade: ASSUMED
|
|
24
|
+
text: >-
|
|
25
|
+
Test files are edited only under a task's licence; adding a test is an addition,
|
|
26
|
+
editing one needs scope
|
|
27
|
+
paths: [tests/**]
|
|
28
|
+
consequence: >-
|
|
29
|
+
The no-test-tampering gate never measured a single landing — no task existed
|
|
30
|
+
— so this row gives the gate a spec once work is minted
|
|
31
|
+
- id: D-4
|
|
32
|
+
grade: ASSUMED
|
|
33
|
+
text: >-
|
|
34
|
+
Work touching governed areas records its decisions in the task log
|
|
35
|
+
paths: [.torve/tasks/**, logs/**]
|
|
36
|
+
consequence: >-
|
|
37
|
+
The decisions-reported gate never measured a landing; this row is the corpus
|
|
38
|
+
layer that turns its no-task skip into something that can fire
|
|
39
|
+
- id: D-5
|
|
40
|
+
grade: ASSUMED
|
|
41
|
+
text: Execution logs carry the declared drift count
|
|
42
|
+
paths: [.torve/tasks/**, logs/**]
|
|
43
|
+
consequence: >-
|
|
44
|
+
The self-audit gate never measured a landing; this row names the log discipline
|
|
45
|
+
the gate reads
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../../schemas/document.json
|
|
2
|
+
id: S-0001
|
|
3
|
+
title: Standing decisions
|
|
4
|
+
kind: design
|
|
5
|
+
status: draft
|
|
6
|
+
implementation: none
|
|
7
|
+
depends_on: []
|
|
8
|
+
informed_by: []
|
|
9
|
+
supersedes: []
|
|
10
|
+
superseded_by: null
|
|
11
|
+
owner: <adopter>
|
|
12
|
+
schema_version: 4
|
|
13
|
+
summary: |-
|
|
14
|
+
The survey found two crossed boundaries and three gates that never measured
|
|
15
|
+
a single landing. The secrets boundary was defended: a key landed in
|
|
16
|
+
`src/leak.py` and the next landing removed it, so that row stands `LOCKED`.
|
|
17
|
+
The source-layout boundary was crossed once and left uncorrected in the
|
|
18
|
+
window, so its row stands `ASSUMED`. The three gates that never measured
|
|
19
|
+
anything for want of a corpus — test licensing, decision recording, and the
|
|
20
|
+
self-audit log — each get an `ASSUMED` row that gives them something to
|
|
21
|
+
measure once work is minted.
|
|
22
|
+
motivation: ''
|
|
23
|
+
current_state: ''
|
|
24
|
+
goals: ''
|
|
25
|
+
non_goals: ''
|
|
26
|
+
design:
|
|
27
|
+
- key: the-survey-findings
|
|
28
|
+
md: |-
|
|
29
|
+
- **`secrets` fired** on landing `f901a7b` ("chore: wire stripe
|
|
30
|
+
credentials"): a new file `src/leak.py` carried an access key. Landing `d55fecb`
|
|
31
|
+
("fix: rotate credentials out of the tree") deleted the file and added a
|
|
32
|
+
`.env.example` placeholder, and measured clean — the boundary was
|
|
33
|
+
defended in the window.
|
|
34
|
+
- **`scope` fired** on landing `8ef5b12` ("chore: deployment script at
|
|
35
|
+
repository root"): `scripts/deploy.sh` landed outside the manifest's
|
|
36
|
+
`src/**` and `.env.example` allow. No later landing corrected it in the
|
|
37
|
+
window, and the tree's `src/` home for product code holds across the
|
|
38
|
+
other four landings.
|
|
39
|
+
- **`no-test-tampering`, `decisions-reported`, `self-audit` skipped every
|
|
40
|
+
landing** with the no-task skip: no contract has ever existed in this
|
|
41
|
+
repository, so nothing gave them a spec to check against. The survey's
|
|
42
|
+
`corpus_adds` names exactly these three — the corpus's absence made
|
|
43
|
+
visible.
|
|
44
|
+
- key: decisions
|
|
45
|
+
md: |-
|
|
46
|
+
| # | Grade | Decision | Paths | Consequence |
|
|
47
|
+
| --- | --- | --- | --- | --- |
|
|
48
|
+
| S-0001/D-1 | `LOCKED` | Credentials never enter the source tree; secrets are injected from the deployment environment | `src/**` `.env.example` | The repository's history defended this boundary: the survey's secrets gate fired when a key landed in `src/leak.py` and the next landing removed it; crossing it again is expensive to undo |
|
|
49
|
+
| S-0001/D-2 | `ASSUMED` | Product code lives under `src/**`; operational scripts live under `scripts/**` | `src/**` `scripts/**` | The survey's scope gate fired once on a root-level deploy script and stayed clean on the other four landings; whether the layout is deliberate is the acceptance edit's call |
|
|
50
|
+
| S-0001/D-3 | `ASSUMED` | Test files are edited only under a task's licence; adding a test is an addition, editing one needs scope | `tests/**` | The no-test-tampering gate never measured a single landing — no task existed — so this row gives the gate a spec once work is minted |
|
|
51
|
+
| S-0001/D-4 | `ASSUMED` | Work touching governed areas records its decisions in the task log | `.torve/tasks/**` `logs/**` | The decisions-reported gate never measured a landing; this row is the corpus layer that turns its no-task skip into something that can fire |
|
|
52
|
+
| S-0001/D-5 | `ASSUMED` | Execution logs carry the declared drift count | `.torve/tasks/**` `logs/**` | The self-audit gate never measured a landing; this row names the log discipline the gate reads |
|
|
53
|
+
tests: ''
|
|
54
|
+
docs: ''
|
|
55
|
+
out_of_scope: ''
|
|
56
|
+
risks: ''
|