simt-dev 0.7.1 → 0.8.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/CHANGELOG.md +36 -1
- package/README.md +169 -80
- package/docs/decisions/ADR-014-workspace-is-configuration.md +1 -1
- package/docs/decisions/ADR-025-a-baseline-is-a-region-in-a-file-the-repo-owns.md +1 -1
- package/docs/decisions/ADR-026-a-config-without-a-region-is-a-file-the-repo-owns.md +1 -1
- package/docs/decisions/ADR-027-the-one-gitattributes-line-that-is-neither-dangerous-nor-empty.md +1 -1
- package/docs/decisions/ADR-028-a-base-file-is-a-floor-so-the-disagreement-it-cannot-repair-becomes-a-check.md +1 -1
- package/docs/decisions/ADR-029-the-pins-a-repository-declares-are-its-own.md +1 -1
- package/docs/decisions/ADR-030-what-a-plan-does-not-ship-is-a-decision-with-a-record.md +1 -1
- package/docs/decisions/ADR-048-a-baseline-carries-only-keys-a-reader-honours.md +1 -1
- package/docs/decisions/ADR-082-the-tracker-override-is-a-manifest-key.md +1 -1
- package/docs/decisions/ADR-126-the-mcp-surface-stays-a-reader-so-there-is-no-write-path-to-build.md +68 -0
- package/docs/decisions/ADR-127-the-mcp-tool-list-is-written-by-hand-and-roots-is-not-asked-for.md +65 -0
- package/docs/decisions/ADR-128-a-research-plan-is-a-plan-and-the-tracker-reads-it.md +42 -0
- package/ecosystems/bun.json +6 -0
- package/ecosystems/cargo.json +25 -0
- package/ecosystems/composer.json +6 -0
- package/ecosystems/dart.json +24 -0
- package/ecosystems/deno.json +21 -0
- package/ecosystems/devcontainers.json +6 -0
- package/ecosystems/docker-compose.json +6 -0
- package/ecosystems/docker.json +6 -0
- package/ecosystems/dotnet.json +25 -0
- package/ecosystems/elixir.json +23 -0
- package/ecosystems/gitsubmodule.json +6 -0
- package/ecosystems/go.json +25 -0
- package/ecosystems/gradle.json +13 -0
- package/ecosystems/maven.json +23 -0
- package/ecosystems/node.json +25 -0
- package/ecosystems/python.json +20 -0
- package/ecosystems/ruby.json +23 -0
- package/ecosystems/swift.json +25 -0
- package/ecosystems/terraform.json +6 -0
- package/ecosystems/uv.json +6 -0
- package/harnesses/antigravity.json +162 -0
- package/harnesses/claude.json +206 -0
- package/harnesses/codex.json +136 -0
- package/harnesses/copilot.json +88 -0
- package/harnesses/cursor.json +140 -0
- package/harnesses/deepseek.json +99 -0
- package/harnesses/gemini.json +122 -0
- package/harnesses/opencode.json +173 -0
- package/package.json +3 -1
- package/rules/mdc/intake-questions.mdc +8 -0
- package/src/advice/advice.mjs +3 -2
- package/src/agenthooks/render.mjs +86 -180
- package/src/agents/render.mjs +15 -18
- package/src/api.mjs +7 -5
- package/src/argv.mjs +19 -0
- package/src/bench/ablate.mjs +3 -4
- package/src/bench/adapters.json +155 -113
- package/src/bench/adapters.mjs +466 -0
- package/src/bench/arms.mjs +333 -0
- package/src/bench/grade.mjs +12 -26
- package/src/bench/graders.mjs +42 -0
- package/src/bench/mine.mjs +17 -535
- package/src/bench/probe-ledger.mjs +149 -0
- package/src/bench/probes.catalog.mjs +918 -0
- package/src/bench/probes.mjs +15 -1037
- package/src/bench/render.mjs +111 -0
- package/src/bench/report.mjs +116 -971
- package/src/bench/run.mjs +164 -881
- package/src/bench/variants.mjs +4 -5
- package/src/bench/workspace.mjs +160 -0
- package/src/brief/assemble.mjs +11 -13
- package/src/ci/dependabot.mjs +25 -55
- package/src/commands/agent.mjs +1 -9
- package/src/commands/agenthook.mjs +66 -35
- package/src/commands/bench.mjs +2 -2
- package/src/commands/ci.mjs +11 -13
- package/src/commands/docs.mjs +88 -0
- package/src/commands/gate.mjs +10 -13
- package/src/commands/harness.mjs +3 -3
- package/src/commands/help.mjs +44 -3
- package/src/commands/hooks.mjs +20 -20
- package/src/commands/ignore.mjs +11 -7
- package/src/commands/impact.mjs +4 -8
- package/src/commands/index.mjs +49 -9
- package/src/commands/init-scan.mjs +90 -0
- package/src/commands/init.mjs +122 -104
- package/src/commands/lease.mjs +67 -18
- package/src/commands/map.mjs +10 -5
- package/src/commands/mcp.mjs +2 -17
- package/src/commands/repoindex.mjs +8 -8
- package/src/commands/rules.mjs +8 -4
- package/src/commands/shared.mjs +12 -16
- package/src/commands/skills.mjs +5 -6
- package/src/commands/skillscompile.mjs +3 -3
- package/src/commands/skillsinstall.mjs +5 -4
- package/src/commands/slice.mjs +199 -64
- package/src/commands/spec.mjs +78 -62
- package/src/commands/status.mjs +24 -12
- package/src/commands/sync.mjs +14 -14
- package/src/commands/tests.mjs +12 -12
- package/src/commands/tokens.mjs +19 -24
- package/src/commands/upgrade.mjs +8 -4
- package/src/commands/why.mjs +6 -13
- package/src/compare/hooksstate.mjs +2 -6
- package/src/compare/learn.mjs +3 -1
- package/src/decisions/index.mjs +3 -2
- package/src/docs/commands.mjs +65 -0
- package/src/ecosystem/records.mjs +219 -0
- package/src/explain.mjs +31 -0
- package/src/gates/index.mjs +385 -0
- package/src/graph/compile.mjs +8 -4
- package/src/graph/load.mjs +2 -1
- package/src/graph/spec.mjs +10 -8
- package/src/harness/records.mjs +143 -0
- package/src/hooks/capability.mjs +5 -3
- package/src/hooks/dispatcher.mjs +26 -32
- package/src/hooks/gates.mjs +12 -2
- package/src/hooks/resolve.mjs +2 -7
- package/src/hooks/where.mjs +2 -7
- package/src/identity.mjs +2 -11
- package/src/index/coverage.mjs +58 -0
- package/src/index/extract.mjs +6 -16
- package/src/index/gate.mjs +1 -1
- package/src/index/govern.mjs +26 -9
- package/src/index/impact.mjs +4 -8
- package/src/index/map.mjs +14 -15
- package/src/index/open.mjs +173 -0
- package/src/index/persist.mjs +224 -57
- package/src/index/store.mjs +82 -39
- package/src/index/tests.mjs +2 -6
- package/src/journal.mjs +16 -11
- package/src/kernel/card.mjs +37 -63
- package/src/kernel/checks.mjs +4 -10
- package/src/lease.mjs +102 -7
- package/src/ledger/index.mjs +124 -17
- package/src/mcp/paginate.mjs +33 -0
- package/src/mcp/schemas.mjs +512 -0
- package/src/mcp/server.mjs +49 -9
- package/src/mcp/tools-facts.mjs +326 -0
- package/src/mcp/tools-read.mjs +221 -0
- package/src/mcp/tools.mjs +4 -1005
- package/src/{bench → measure}/corpus.mjs +1 -1
- package/src/measure/metrics.mjs +236 -0
- package/src/measure/records.mjs +211 -0
- package/src/measure/stats.mjs +538 -0
- package/src/measure/task-schema.mjs +125 -0
- package/src/measure/tasks.mjs +69 -0
- package/src/memory/decide.mjs +6 -15
- package/src/memory/lesson-text.mjs +61 -0
- package/src/memory/lessons.mjs +29 -82
- package/src/name.mjs +7 -0
- package/src/output/index.mjs +122 -31
- package/src/packs/manage.mjs +15 -9
- package/src/plan/index.mjs +1 -1
- package/src/plugins.mjs +22 -16
- package/src/prbody.mjs +7 -11
- package/src/projection/loaders.mjs +7 -692
- package/src/projection/manifest.mjs +10 -435
- package/src/projection/mdc.mjs +7 -8
- package/src/projection/project.mjs +126 -221
- package/src/projection/region.mjs +561 -0
- package/src/projection/rules.mjs +16 -547
- package/src/projection/surfaces.mjs +43 -210
- package/src/projection/targets.mjs +5 -5
- package/src/repo-root.mjs +13 -1
- package/src/resolve/eval.mjs +2 -1
- package/src/resolve/fingerprint.mjs +0 -7
- package/src/resolve/resolve.mjs +1 -41
- package/src/review/critic.mjs +8 -12
- package/src/run.mjs +98 -0
- package/src/secrets.mjs +14 -22
- package/src/state/events.mjs +129 -0
- package/src/status-snapshot.mjs +233 -0
- package/src/status.mjs +2 -6
- package/src/sys/git.mjs +82 -0
- package/src/{bench/process.mjs → sys/proc.mjs} +28 -5
- package/src/testing/parsers.mjs +265 -0
- package/src/testing/patches.mjs +23 -0
- package/src/testing/paths.mjs +49 -0
- package/src/testing/runners.mjs +186 -0
- package/src/testing/vault.mjs +68 -0
- package/src/text/frontmatter.mjs +49 -0
- package/src/text/tokens.mjs +52 -0
- package/src/toolwords.mjs +1 -1
- package/src/util/fs.mjs +20 -0
- package/src/util/sort.mjs +12 -0
- package/src/workspace.mjs +3 -1
- package/src/write/plan.mjs +82 -0
- package/templates/plan/tracker.json +1 -0
- package/docs/decisions/ADR-033-three-plan-rows-closed-by-decision-not-by-authoring.md +0 -82
- package/docs/decisions/ADR-102-the-two-queued-review-rows-are-closed-by-ruling.md +0 -49
- package/src/bench/tasks.mjs +0 -36
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// The token split and the two stopword lists, in one place.
|
|
2
|
+
//
|
|
3
|
+
// The two lists are deliberately NOT merged. The resolver's list is the English
|
|
4
|
+
// filler a task string carries ("fix the thing"), hand-authored because a resolver
|
|
5
|
+
// nobody can review is not a resolver; the index's list is the vocabulary a task
|
|
6
|
+
// about code carries ("file", "test", "line"), sized for a different signal. Merging
|
|
7
|
+
// them would change what each one ranks, and a ranking change is a behaviour change
|
|
8
|
+
// this deduplication was not asked to make.
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Split a task string into comparable tokens.
|
|
12
|
+
*
|
|
13
|
+
* Length 2 is kept. The floor used to be 3, and it dropped the most specific words in
|
|
14
|
+
* this domain: `d1`, `r2`, `kv`, `ci` are two-letter vocabulary, not noise, and a task
|
|
15
|
+
* saying "fix d1 migration" lost the one word that identified the change. The cost is
|
|
16
|
+
* that six stopwords of two letters (`in on of or an so`) now reach the summary signal,
|
|
17
|
+
* which is S04's finding and not something this change can resolve on its own - the
|
|
18
|
+
* remedy there is a stopword list, not a longer minimum.
|
|
19
|
+
*/
|
|
20
|
+
export function tokenize(text) {
|
|
21
|
+
return String(text ?? '')
|
|
22
|
+
.toLowerCase()
|
|
23
|
+
.split(/[^a-z0-9]+/)
|
|
24
|
+
.filter((t) => t.length > 1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The English filler a task string carries. Hand-authored rather than derived, for the
|
|
29
|
+
* same reason the capability aliases are: a resolver nobody can review is not a
|
|
30
|
+
* resolver.
|
|
31
|
+
*/
|
|
32
|
+
export const STOPWORDS = new Set([
|
|
33
|
+
'about', 'after', 'all', 'also', 'and', 'an', 'any', 'are', 'as', 'at', 'be', 'because',
|
|
34
|
+
'been', 'before', 'being', 'both', 'but', 'by', 'can', 'could', 'did', 'do', 'does', 'each',
|
|
35
|
+
'for', 'from', 'had', 'has', 'have', 'he', 'her', 'here', 'his', 'how', 'if', 'in', 'into',
|
|
36
|
+
'is', 'it', 'its', 'just', 'like', 'make', 'many', 'may', 'me', 'more', 'most', 'must', 'my',
|
|
37
|
+
'no', 'not', 'now', 'of', 'off', 'on', 'one', 'only', 'onto', 'or', 'other', 'our', 'out',
|
|
38
|
+
'over', 'own', 'per', 'same', 'see', 'set', 'she', 'should', 'so', 'some', 'such', 'than',
|
|
39
|
+
'that', 'the', 'their', 'them', 'then', 'there', 'these', 'they', 'this', 'those', 'to', 'too',
|
|
40
|
+
'two', 'under', 'up', 'us', 'use', 'used', 'using', 'very', 'was', 'way', 'we', 'were', 'what',
|
|
41
|
+
'when', 'where', 'which', 'while', 'who', 'why', 'will', 'with', 'within', 'without', 'would',
|
|
42
|
+
'you', 'your',
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
/** The code vocabulary a task about a tree carries, for the index's term signal. */
|
|
46
|
+
export const INDEX_STOP = new Set([
|
|
47
|
+
'this', 'that', 'with', 'from', 'have', 'been', 'into', 'only', 'when', 'what',
|
|
48
|
+
'which', 'their', 'about', 'after', 'before', 'where', 'there', 'these', 'those',
|
|
49
|
+
'would', 'could', 'should', 'every', 'other', 'than', 'then', 'them', 'they',
|
|
50
|
+
'your', 'will', 'does', 'file', 'files', 'test', 'tests', 'line', 'lines', 'code',
|
|
51
|
+
'also', 'just', 'more', 'some', 'such', 'each', 'same', 'over', 'used', 'using',
|
|
52
|
+
]);
|
package/src/toolwords.mjs
CHANGED
|
@@ -23,7 +23,7 @@ import { LESSON_KEYS } from './memory/lessons.mjs';
|
|
|
23
23
|
import { DECISION_KEYS } from './memory/decide.mjs';
|
|
24
24
|
import { PROMPT_WORDS } from './mcp/prompts.mjs';
|
|
25
25
|
import { AGENT_STEM, SKILL_STEM } from './agents/render.mjs';
|
|
26
|
-
import { CORPUS_KIND } from './
|
|
26
|
+
import { CORPUS_KIND } from './measure/corpus.mjs';
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* `simt-` names that belong to this tool and never to a repository.
|
package/src/util/fs.mjs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Small file and output helpers with two or more call sites, too small to earn
|
|
2
|
+
// a module apiece.
|
|
3
|
+
|
|
4
|
+
import { readFile } from 'node:fs/promises';
|
|
5
|
+
|
|
6
|
+
/** Read a file as UTF-8, answering null when it is not there. */
|
|
7
|
+
export async function readIfExists(path) {
|
|
8
|
+
try {
|
|
9
|
+
return await readFile(path, 'utf8');
|
|
10
|
+
} catch {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** `1234567`, never `1,234,567`: two machines must print the same bytes (ADR-013).
|
|
16
|
+
* `toLocaleString` output is locale-dependent, and these commands exist so that two
|
|
17
|
+
* machines produce two numbers a pull request can compare. */
|
|
18
|
+
export function plainNumber(n) {
|
|
19
|
+
return String(n);
|
|
20
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// The one string comparison for every sort that orders paths, names and ids.
|
|
2
|
+
//
|
|
3
|
+
// Seven copies of the same three-line comparator grew up under src/, spelled two
|
|
4
|
+
// different ways, and a divergence in any one of them would quietly reorder a list
|
|
5
|
+
// a reader has memorized. One definition, one order.
|
|
6
|
+
|
|
7
|
+
/** Deterministic string order: -1, 0 or 1. */
|
|
8
|
+
export function cmp(a, b) {
|
|
9
|
+
if (a < b) return -1;
|
|
10
|
+
if (a > b) return 1;
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
package/src/workspace.mjs
CHANGED
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
// confidently wrong.
|
|
22
22
|
|
|
23
23
|
import { readFile } from 'node:fs/promises';
|
|
24
|
+
|
|
25
|
+
import { namedRoot } from './repo-root.mjs';
|
|
24
26
|
import { existsSync } from 'node:fs';
|
|
25
27
|
import { homedir, platform as osPlatform } from 'node:os';
|
|
26
28
|
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
@@ -311,7 +313,7 @@ function absolute(p, base = process.cwd()) {
|
|
|
311
313
|
* answers it from the filesystem rather than from a guess.
|
|
312
314
|
*/
|
|
313
315
|
export async function targetRoot(flags = {}, positional = []) {
|
|
314
|
-
const explicit = flags
|
|
316
|
+
const explicit = namedRoot(flags, positional);
|
|
315
317
|
if (explicit) {
|
|
316
318
|
return { root: absolute(explicit), source: 'flag', detail: explicit, ws: null };
|
|
317
319
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// One change record, and the one function that applies it (review 0003 Q68).
|
|
2
|
+
//
|
|
3
|
+
// Fourteen writers hand-roll the same five steps: read the before bytes, decide create or
|
|
4
|
+
// update, write through the journal, commit the set, print the diff. They do not all do
|
|
5
|
+
// them in the same order, and the differences are defects rather than decisions - a
|
|
6
|
+
// writer that skipped the journal (the tracker, the lock, `skills compile`) could not be
|
|
7
|
+
// undone, and one that read the before bytes after writing produced a diff against
|
|
8
|
+
// itself.
|
|
9
|
+
//
|
|
10
|
+
// A change is data: what the path will hold, what it holds now, who owns it and why it
|
|
11
|
+
// changes. `applyPlan` is the only place that knows about journals, directories and
|
|
12
|
+
// `--yes`, so a writer states the change and nothing else.
|
|
13
|
+
//
|
|
14
|
+
// The record carries no `action` from the caller. Create, update, remove and unchanged
|
|
15
|
+
// are derived from `before` and `after`, because a writer that passes an action it
|
|
16
|
+
// computed by hand is the bug this replaces.
|
|
17
|
+
import { isAbsolute, join } from 'node:path';
|
|
18
|
+
|
|
19
|
+
import { commitJournal, journaledRemoveFile, journaledWriteFile } from '../journal.mjs';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* One change to one path.
|
|
23
|
+
*
|
|
24
|
+
* `kind: 'remove'` is a deletion, and `after` is then null. `owner` and `reason` are for
|
|
25
|
+
* the report a person reads: which writer owns the file and why it is changing. `mode` is
|
|
26
|
+
* permission bits for a file that must be executable, and rides on the same entry so
|
|
27
|
+
* `undo` restores the mode it found.
|
|
28
|
+
*/
|
|
29
|
+
export function change({ path, kind = 'file', before, after, owner, reason, mode }) {
|
|
30
|
+
if (kind !== 'file' && kind !== 'remove') throw new Error(`unknown change kind: ${kind}`);
|
|
31
|
+
return {
|
|
32
|
+
path,
|
|
33
|
+
kind,
|
|
34
|
+
before,
|
|
35
|
+
after,
|
|
36
|
+
owner: owner ?? null,
|
|
37
|
+
reason: reason ?? null,
|
|
38
|
+
mode,
|
|
39
|
+
action: actionOf(kind, before, after),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function actionOf(kind, before, after) {
|
|
44
|
+
if (kind === 'remove') return before === null ? 'unchanged' : 'remove';
|
|
45
|
+
if (before === after) return 'unchanged';
|
|
46
|
+
if (before === null) return 'create';
|
|
47
|
+
return 'update';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** The changes that would do something, in the order the caller listed them. */
|
|
51
|
+
export function pending(changes) {
|
|
52
|
+
return (changes ?? []).filter((c) => c.action !== 'unchanged');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Apply the plan, or report it.
|
|
57
|
+
*
|
|
58
|
+
* Without `mode.apply` nothing touches the disk and the pending paths come back as
|
|
59
|
+
* `pending`: a rehearsal and a real run answer the same question with the same plan, and
|
|
60
|
+
* the only difference is whether the bytes moved. With it, every change is journaled into
|
|
61
|
+
* one set under `label`, so `undo` restores the run rather than one file of it.
|
|
62
|
+
*
|
|
63
|
+
* A writer whose run is more than one plan - `init` writes a manifest, an identity and a
|
|
64
|
+
* set of targets and commits once - passes its own `journal` and `commit: false`. The
|
|
65
|
+
* entries land in the caller's set, so the run stays one undoable step rather than one
|
|
66
|
+
* step per plan.
|
|
67
|
+
*/
|
|
68
|
+
export async function applyPlan(root, changes, { mode, label, journal: shared, commit = true } = {}) {
|
|
69
|
+
const todo = pending(changes);
|
|
70
|
+
if (todo.length === 0) return { applied: false, written: [], pending: [], journal: [] };
|
|
71
|
+
if (!mode?.apply) return { applied: false, written: [], pending: todo.map((c) => c.path), journal: [] };
|
|
72
|
+
|
|
73
|
+
const journal = shared ?? [];
|
|
74
|
+
const first = journal.length;
|
|
75
|
+
for (const c of todo) {
|
|
76
|
+
const path = isAbsolute(c.path) ? c.path : join(root, c.path);
|
|
77
|
+
if (c.kind === 'remove') await journaledRemoveFile(root, journal, path);
|
|
78
|
+
else await journaledWriteFile(root, journal, path, c.after, c.mode === undefined ? {} : { mode: c.mode });
|
|
79
|
+
}
|
|
80
|
+
if (commit && journal.length > first) await commitJournal(root, label, journal);
|
|
81
|
+
return { applied: true, written: todo.map((c) => c.path), pending: [], journal };
|
|
82
|
+
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# ADR-033 — three plan rows closed by decision, not by authoring
|
|
2
|
-
|
|
3
|
-
Status: accepted · 2026-10-08
|
|
4
|
-
**Affects:** `docs/plans/0001-centralise-agent-rules.md` §3.1 row 3, §6 phase 6, §6 phase 7.
|
|
5
|
-
Ships no rule text. **Refuses:** the seven agent policies row 3 asks for, the twin collapse
|
|
6
|
-
phase 6 asks for, and untracking the two committed `local.properties` files phase 7 does not
|
|
7
|
-
mention but whose existence made the sweep look unfinished.
|
|
8
|
-
|
|
9
|
-
## Context
|
|
10
|
-
|
|
11
|
-
Closing plan 0001 meant auditing each row against the tree rather than against the plan's own
|
|
12
|
-
prose, because the plan was written on 2026-10-05 and three things changed underneath it. This
|
|
13
|
-
record is the audit's residue: three items that read as unfinished work and are not.
|
|
14
|
-
|
|
15
|
-
Row 3 asked for eight agent policies as separate files. Seven were never authored. A search for
|
|
16
|
-
their source material across every tracked `*.md` and `*.mdc` in the estate returns two files,
|
|
17
|
-
neither of which is a policy: they are a progress ledger and a completed UX plan that happen to
|
|
18
|
-
contain the phrases. The three most specific of the eight — the 70/30 quality-versus-performance
|
|
19
|
-
split, the 12-state coverage list, the matrix-trigger heuristic — have no source anywhere. Writing
|
|
20
|
-
them would mean inventing doctrine this estate never agreed to, into `rules/core.md`, from where
|
|
21
|
-
every adopted repo would inherit it.
|
|
22
|
-
|
|
23
|
-
Phase 6 asked to "collapse the 7 drifted Social skill twins to canonical + stub". The registry's
|
|
24
|
-
`sources.role` mechanism landed the same evening, two hours after the plan was authored, and
|
|
25
|
-
answers the row directly. All three resolvers select `role === 'canonical'` and nothing else —
|
|
26
|
-
`src/commands/skills.mjs` twice, `src/commands/skillsinstall.mjs:291`, `src/mcp/tools.mjs:192` — so
|
|
27
|
-
a copy declared `duplicate` or `variant` is never installed. The one pair that genuinely had to be
|
|
28
|
-
collapsed, `add-country-galaxy`, is already a stub in `repo-14` pointing at the API repo.
|
|
29
|
-
|
|
30
|
-
Phase 7 asked for a sweep of hardcoded absolute paths. The sweep found 17 tracked files. Six were
|
|
31
|
-
fixed. The two Android `local.properties` files were not, and were nearly fixed by reflex.
|
|
32
|
-
|
|
33
|
-
## Rulings
|
|
34
|
-
|
|
35
|
-
1. **A row is closed by ruling on it when the thing it asks for was never a decision anyone made.**
|
|
36
|
-
Row 3's eight policies are closed: the four claims `rules/core.md` already carries — the
|
|
37
|
-
minimum viable team, never weakening a security control, anti-overclaim, and a stated agent
|
|
38
|
-
budget that never converts a failure into an approval — are the doctrine, and they ship. The
|
|
39
|
-
other four, including the 70/30 split, the 12-state list and the matrix-trigger heuristic, are
|
|
40
|
-
recorded here as unmade. If one is wanted it needs someone who held the original
|
|
41
|
-
conversation, not someone reconstructing it from a table cell.
|
|
42
|
-
|
|
43
|
-
2. **A mechanism that supersedes a row retires the row, and the deletion is the wrong move.** The
|
|
44
|
-
`sources.role` vocabulary already distinguishes `canonical`, `duplicate`, `variant`, `stub` and
|
|
45
|
-
`deprecated`, and `graph lint` passes with all of them in use. Deleting a `duplicate` copy would
|
|
46
|
-
remove a version-pinned tool from a repo that can still run it, and nothing would detect the loss
|
|
47
|
-
because resolution never read those bytes. Phase 6's twin collapse is therefore closed as
|
|
48
|
-
already answered, at `a9983c8`.
|
|
49
|
-
|
|
50
|
-
3. **`local.properties` stays tracked.** Both `repo-05` and `repo-03` commit it, and both
|
|
51
|
-
`.gitignore` files have the conventional `# local.properties` line commented out at lines 22 and
|
|
52
|
-
24 — a deliberate override of Android's own convention, not an oversight. Untracking them would
|
|
53
|
-
be a house-style change made while closing a plan, and a build machine that checks out without
|
|
54
|
-
an SDK would stop building. It stays, and plan 0001 says so, so the next sweep does not
|
|
55
|
-
rediscover it as a defect.
|
|
56
|
-
|
|
57
|
-
## Consequences
|
|
58
|
-
|
|
59
|
-
Row 3 reads "done, four of eight" rather than "partial". Phase 6's twin item reads "superseded"
|
|
60
|
-
rather than "outstanding". The estate keeps two `local.properties` files whose `sdk.dir` names a
|
|
61
|
-
developer's home directory, by decision.
|
|
62
|
-
|
|
63
|
-
The registry's byte counts moved with the two skill bodies corrected in the same pass, because a
|
|
64
|
-
declared source's identity is its size (ADR-015): `cloudflare` 384277 → 384869 and
|
|
65
|
-
`production-quality-review` 5869 → 5904. That changed the provenance digest (ADR-032), so all
|
|
66
|
-
fourteen adopted repos were re-stamped afterwards rather than left pinning a value this tool can no
|
|
67
|
-
longer produce.
|
|
68
|
-
|
|
69
|
-
## Rejected
|
|
70
|
-
|
|
71
|
-
**Authoring the seven agent policies.** The plan's one-line summaries are not enough to write seven
|
|
72
|
-
files of rule text, and these rules reach every adopted repo. This is ADR-030's exact shape: an
|
|
73
|
-
unmade decision is not a gap to fill by invention.
|
|
74
|
-
|
|
75
|
-
**Collapsing `graphify` and `parallel-feature-team`.** Both are declared `duplicate` with matching
|
|
76
|
-
byte counts, so they look like the obvious candidates. `graphify` is `vendored: true` — an
|
|
77
|
-
84 534-byte, ten-file, version-pinned tool present in both one repository on purpose. Deleting
|
|
78
|
-
repo-14's copy would leave nothing to detect the loss, because resolution only ever read the
|
|
79
|
-
canonical copy.
|
|
80
|
-
|
|
81
|
-
**Untracking `local.properties`.** An Android SDK path is machine state, and two repos chose to
|
|
82
|
-
share it. That is the repo's call to reverse, not a plan's defect sweep.
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
simt-affects: ["docs/reviews/0002-full-review-adoption-and-public-release.md"]
|
|
3
|
-
simt-supersedes: []
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# ADR-102 — the two rows review 0002 left queued are closed by ruling
|
|
7
|
-
|
|
8
|
-
Status: **accepted** · 2026-10-28
|
|
9
|
-
|
|
10
|
-
## Context
|
|
11
|
-
|
|
12
|
-
Review 0002's §3 tracker is the only tracker of slice state, and two rows in it
|
|
13
|
-
still read Queued while everything around them shipped: S38 (workspace token
|
|
14
|
-
cost) and S39 (estate policy as a pack). Both rows' evidence cells are
|
|
15
|
-
palimpsests — notes from three different landings disagreeing about what is
|
|
16
|
-
still open — so reading them as a work list sends the next reader to build what
|
|
17
|
-
is already built. Closing plan 0001 meant the same audit, and ADR-033 is the
|
|
18
|
-
precedent: rows closed by saying what shipped, what was refused by ruling, and
|
|
19
|
-
where the remainder lives, not by authoring what they asked for.
|
|
20
|
-
|
|
21
|
-
## Ruling
|
|
22
|
-
|
|
23
|
-
1. **S38 is Complete.** The instrument shipped (`simt tokens`, ADR-064), the
|
|
24
|
-
declaration shipped (`budget.bytes` beside `limits` and `gates`, ADR-072),
|
|
25
|
-
and the gate raises it as a finding through one `budgetFinding` read from
|
|
26
|
-
one place by both `tokens` and `check` — the "still open" clause the row's
|
|
27
|
-
first note ends on. Kernel-line packing shipped with it (R07's `mode:
|
|
28
|
-
kernel`, R08's budget compilation). Blocking enforcement is refused, not
|
|
29
|
-
outstanding: a gate that fails a repository for exceeding a ceiling it set
|
|
30
|
-
itself, when nothing was cut, has no repair except lowering the declared
|
|
31
|
-
number (ADR-072). The one genuine remainder is the kernel-default
|
|
32
|
-
compliance study, and it is owned by plan 0003 R07's own note, not by this
|
|
33
|
-
row — the study gates making `kernel` the default, which no row asks to
|
|
34
|
-
decide here.
|
|
35
|
-
|
|
36
|
-
2. **S39 is Complete.** The mechanism shipped (packs vendored and digest-pinned,
|
|
37
|
-
ADR-065; measured ΔR, plan 0003 R45). P4's pack-carries-the-registry line was
|
|
38
|
-
superseded by ADR-061, which made the registry workspace data, so there is
|
|
39
|
-
no registry-carrying pack to build. The remaining half — moving estate
|
|
40
|
-
policy into a pack — is the estate's own commit: no estate content may enter
|
|
41
|
-
this repository, and a row that waits on another repository's commit is
|
|
42
|
-
closed by recording whose commit it waits on.
|
|
43
|
-
|
|
44
|
-
## Consequences
|
|
45
|
-
|
|
46
|
-
- The §3 tracker reads Complete on both rows, with this record as the evidence,
|
|
47
|
-
so the next audit starts from rulings rather than from mid-flight notes.
|
|
48
|
-
- A reader asking for a blocking budget gate or a registry-carrying pack gets
|
|
49
|
-
the refusal and its reason instead of an open row that looks like a promise.
|
package/src/bench/tasks.mjs
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
// Mined task descriptors, read back from the tool state's `bench/tasks/` directory (plan 0003 R01).
|
|
2
|
-
//
|
|
3
|
-
// Extracted from bench/run.mjs on its second real reader (ADR-002): the R40 advice engine
|
|
4
|
-
// needs the two facts a run record does not carry — the prompt, which classifies the task,
|
|
5
|
-
// and the gold stat, which says how many files the change touched. A second private loader
|
|
6
|
-
// beside the first would drift the first time one learned a filter the other lacked.
|
|
7
|
-
//
|
|
8
|
-
// Deterministic by construction: the directory is read sorted, the filter is exact, and no
|
|
9
|
-
// part of this touches a model, a network or a clock.
|
|
10
|
-
import { readdir, readFile } from 'node:fs/promises';
|
|
11
|
-
import { join, resolve } from 'node:path';
|
|
12
|
-
import { STATE_DIR } from '../name.mjs';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Load mined benchmark task descriptors.
|
|
16
|
-
*
|
|
17
|
-
* @param {string} root the repository
|
|
18
|
-
* @param {string[]} [filterIds] exact task ids to keep; empty means load them all
|
|
19
|
-
* @returns descriptor objects sorted by id (id, base, sourceCommit, prompt, testCmd,
|
|
20
|
-
* f2p, p2p, gold {files, linesAdded, linesRemoved}, vault)
|
|
21
|
-
*/
|
|
22
|
-
export async function loadTasks(root, filterIds = []) {
|
|
23
|
-
const tasksDir = join(resolve(root), STATE_DIR, 'bench', 'tasks');
|
|
24
|
-
const entries = (await readdir(tasksDir).catch(() => []))
|
|
25
|
-
.filter((f) => f.endsWith('.json'))
|
|
26
|
-
.sort();
|
|
27
|
-
|
|
28
|
-
const filterSet = new Set(filterIds);
|
|
29
|
-
const tasks = [];
|
|
30
|
-
for (const entry of entries) {
|
|
31
|
-
const data = JSON.parse(await readFile(join(tasksDir, entry), 'utf8'));
|
|
32
|
-
if (filterSet.size > 0 && !filterSet.has(data.id)) continue;
|
|
33
|
-
tasks.push(data);
|
|
34
|
-
}
|
|
35
|
-
return tasks.sort((a, b) => a.id.localeCompare(b.id));
|
|
36
|
-
}
|