@omne-harness/repo-toolchain 0.0.17 → 0.0.19
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/README.md +36 -12
- package/README_ZH.md +91 -49
- package/dist/acceptance/lock.d.ts +8 -0
- package/dist/acceptance/lock.d.ts.map +1 -1
- package/dist/acceptance/lock.js +99 -20
- package/dist/acceptance/lock.js.map +1 -1
- package/dist/arch/conformance-model.d.ts +0 -17
- package/dist/arch/conformance-model.d.ts.map +1 -1
- package/dist/arch/conformance-model.js.map +1 -1
- package/dist/arch/conformance.d.ts +14 -2
- package/dist/arch/conformance.d.ts.map +1 -1
- package/dist/arch/conformance.js +22 -14
- package/dist/arch/conformance.js.map +1 -1
- package/dist/arch/constraints.d.ts.map +1 -1
- package/dist/arch/constraints.js +9 -80
- package/dist/arch/constraints.js.map +1 -1
- package/dist/arch/extract.d.ts +6 -0
- package/dist/arch/extract.d.ts.map +1 -1
- package/dist/arch/extract.js +6 -1
- package/dist/arch/extract.js.map +1 -1
- package/dist/arch/source.d.ts.map +1 -1
- package/dist/arch/source.js +11 -2
- package/dist/arch/source.js.map +1 -1
- package/dist/core/subject.d.ts +0 -2
- package/dist/core/subject.d.ts.map +1 -1
- package/dist/core/subject.js +0 -4
- package/dist/core/subject.js.map +1 -1
- package/dist/declarations/api-baseline.d.ts +2 -2
- package/dist/declarations/api-baseline.js +2 -2
- package/dist/declarations/api-compare.d.ts.map +1 -1
- package/dist/declarations/api-compare.js +15 -7
- package/dist/declarations/api-compare.js.map +1 -1
- package/dist/declarations/contract-api.d.ts +4 -4
- package/dist/declarations/contract-api.d.ts.map +1 -1
- package/dist/declarations/contract-api.js +7 -7
- package/dist/declarations/contract-api.js.map +1 -1
- package/dist/deps/cli.js +4 -15
- package/dist/deps/cli.js.map +1 -1
- package/dist/deps/graph.d.ts +43 -13
- package/dist/deps/graph.d.ts.map +1 -1
- package/dist/deps/graph.js +479 -42
- package/dist/deps/graph.js.map +1 -1
- package/dist/loop/baseline-cache.d.ts +21 -0
- package/dist/loop/baseline-cache.d.ts.map +1 -0
- package/dist/loop/baseline-cache.js +135 -0
- package/dist/loop/baseline-cache.js.map +1 -0
- package/dist/loop/health-render.js +2 -2
- package/dist/loop/health-render.js.map +1 -1
- package/dist/loop/health.d.ts +2 -1
- package/dist/loop/health.d.ts.map +1 -1
- package/dist/loop/health.js +11 -4
- package/dist/loop/health.js.map +1 -1
- package/dist/loop/hook-child.d.ts +2 -0
- package/dist/loop/hook-child.d.ts.map +1 -0
- package/dist/loop/hook-child.js +13 -0
- package/dist/loop/hook-child.js.map +1 -0
- package/dist/loop/hook-graph.d.ts +36 -0
- package/dist/loop/hook-graph.d.ts.map +1 -0
- package/dist/loop/hook-graph.js +200 -0
- package/dist/loop/hook-graph.js.map +1 -0
- package/dist/loop/hook-job.d.ts +8 -0
- package/dist/loop/hook-job.d.ts.map +1 -0
- package/dist/loop/hook-job.js +31 -0
- package/dist/loop/hook-job.js.map +1 -0
- package/dist/loop/hook-measure.d.ts +8 -1
- package/dist/loop/hook-measure.d.ts.map +1 -1
- package/dist/loop/hook-measure.js +28 -11
- package/dist/loop/hook-measure.js.map +1 -1
- package/dist/loop/hook-process.d.ts +34 -0
- package/dist/loop/hook-process.d.ts.map +1 -0
- package/dist/loop/hook-process.js +91 -0
- package/dist/loop/hook-process.js.map +1 -0
- package/dist/loop/hook.d.ts +39 -14
- package/dist/loop/hook.d.ts.map +1 -1
- package/dist/loop/hook.js +104 -51
- package/dist/loop/hook.js.map +1 -1
- package/dist/loop/proposals.js +1 -1
- package/dist/loop/proposals.js.map +1 -1
- package/dist/loop/run.d.ts +3 -14
- package/dist/loop/run.d.ts.map +1 -1
- package/dist/loop/run.js +6 -26
- package/dist/loop/run.js.map +1 -1
- package/dist/loop/sensors/conformance.d.ts +7 -1
- package/dist/loop/sensors/conformance.d.ts.map +1 -1
- package/dist/loop/sensors/conformance.js +20 -9
- package/dist/loop/sensors/conformance.js.map +1 -1
- package/dist/loop/status.d.ts +2 -5
- package/dist/loop/status.d.ts.map +1 -1
- package/dist/loop/status.js +0 -2
- package/dist/loop/status.js.map +1 -1
- package/dist/loop/stop-hook.js +21 -5
- package/dist/loop/stop-hook.js.map +1 -1
- package/dist/loop/tool-root.d.ts +6 -0
- package/dist/loop/tool-root.d.ts.map +1 -0
- package/dist/loop/tool-root.js +18 -0
- package/dist/loop/tool-root.js.map +1 -0
- package/dist/metrics/cli.js +72 -36
- package/dist/metrics/cli.js.map +1 -1
- package/dist/metrics/coverage.d.ts +60 -4
- package/dist/metrics/coverage.d.ts.map +1 -1
- package/dist/metrics/coverage.js +251 -55
- package/dist/metrics/coverage.js.map +1 -1
- package/dist/product/scenarios.d.ts.map +1 -1
- package/dist/product/scenarios.js +3 -2
- package/dist/product/scenarios.js.map +1 -1
- package/package.json +1 -1
- package/dist/arch/group-cycles.d.ts +0 -32
- package/dist/arch/group-cycles.d.ts.map +0 -1
- package/dist/arch/group-cycles.js +0 -69
- package/dist/arch/group-cycles.js.map +0 -1
- package/dist/loop/hook-thread.d.ts +0 -11
- package/dist/loop/hook-thread.d.ts.map +0 -1
- package/dist/loop/hook-thread.js +0 -31
- package/dist/loop/hook-thread.js.map +0 -1
- package/dist/loop/hook-worker.d.ts +0 -2
- package/dist/loop/hook-worker.d.ts.map +0 -1
- package/dist/loop/hook-worker.js +0 -23
- package/dist/loop/hook-worker.js.map +0 -1
package/README.md
CHANGED
|
@@ -16,6 +16,23 @@ Three unpublished tool members import this package through its subpaths. This pa
|
|
|
16
16
|
- The runner repository is `OMNE_RUNNER_ROOT`. When it is not set, it is the checked repository. Dependency rules (`.dependency-cruiser.cjs`, `tsconfig.base.json`), the direction rows of `docs/architecture/constraints.json` (schema 3, see the [conformance contract](src/arch/CONFORMANCE.md#方向行) and [Dependency directions](#dependency-directions)) and configuration come only from the runner repository, so a checked tree cannot change them.
|
|
17
17
|
- Configuration is in [`repo-toolchain.config.json`](../../repo-toolchain.config.json) at the repository root, in the sections `loop`, `metrics`, `acceptanceLock` and `contractApi`. Each command reads only its own section. A missing file, a missing section that a command reads, or an unknown section is an error. No defaults apply. Version 0.0.10 is the first version that accepts the `contractApi` section. Earlier versions reject it.
|
|
18
18
|
- dependency-cruiser needs TypeScript to parse `.ts` files. With pnpm, add `typescript` to dependency-cruiser under `packageExtensions` in `pnpm-workspace.yaml`. If TypeScript is not found, the dependency check exits with an error. It does not pass with the `.ts` files left out.
|
|
19
|
+
- The dependency graph of the working tree is cached in `<git-common-dir>/omne-dep-graph/working-<fingerprint>.json`, next to the per-commit baseline graphs. The fingerprint covers every input that can change the graph:
|
|
20
|
+
- the graph format version and the dependency-cruiser version
|
|
21
|
+
- the rule file and the loaded rules, and `tsconfig.base.json` with its `extends` chain
|
|
22
|
+
- the HEAD commit
|
|
23
|
+
- the paths and contents of all uncommitted and untracked files. The scan roots do not filter them, because dependency-cruiser resolves import targets outside the scan roots.
|
|
24
|
+
- the ignored paths. The scan roots do not filter them either: a directory counts only by presence, a single file by content.
|
|
25
|
+
- the ignored-directory decision
|
|
26
|
+
- the contents of `pnpm-lock.yaml` and `node_modules/.modules.yaml`
|
|
27
|
+
- the content digest of the graph code that runs (`src/deps/graph.ts`), so the pinned release and the source version do not hit each other's entries on the same HEAD. The baseline graph cache key includes it too. Changes in other modules that it imports still need a graph format version bump.
|
|
28
|
+
|
|
29
|
+
A hit does not start dependency-cruiser and returns the same bytes as a fresh run. A file that cannot be read, is not valid JSON or does not match is a miss. Only the 10 most recently used entries are kept.
|
|
30
|
+
- `OMNE_DEP_GRAPH_CACHE=0` turns the cache off.
|
|
31
|
+
- With `OMNE_ADMISSION=1` the command does not read the cache. It computes the graph as usual and writes it. An unset or empty value means not admission. Any other value is an error, as in the test runner.
|
|
32
|
+
- After the graph is computed, the command checks the fingerprint again. If an input changed during the run, it does not write the cache. When stderr is a terminal, it prints one line.
|
|
33
|
+
- The graph is reported on stderr as hit or miss only when stderr is a terminal.
|
|
34
|
+
- When the cache is written, the command also records a check list: the imports of modules that are not in an ignored directory and that resolve to a file in an ignored directory (not `node_modules`, which the lock file and `.modules.yaml` cover). The list records the content digest of each file. Before a hit, the command checks each file again. If a file is deleted or its content changed, the command treats the lookup as a miss and computes the graph again.
|
|
35
|
+
- The check list records only files that imports already resolve to. If an import could not be resolved before and a file for it appears later in an ignored directory, the fingerprint does not change and the cache can still report the old failure. It does not let the import pass. If a new file in an ignored directory makes an existing import resolve to it instead, the cache does not see this either.
|
|
19
36
|
|
|
20
37
|
## Default baseline
|
|
21
38
|
|
|
@@ -63,16 +80,9 @@ Version 0.0.12 is the first version in which `omne-deps` checks the direction ro
|
|
|
63
80
|
- No direction rows: when the runner has no `constraints.json`, the command prints that it did not check directions, and the exit code comes from the other findings. A schema 1 or 2 file, or a schema 3 file without `directions`, prints that there are no direction rows.
|
|
64
81
|
- Exit 2: `constraints.json` does not parse, fails validation, fails the check of its cited sources, or `docs/architecture/constraints.json` and `.meta_harness/design/architecture/constraints.json` both exist. The command reads the file before it runs dependency-cruiser.
|
|
65
82
|
|
|
66
|
-
##
|
|
83
|
+
## Cycles
|
|
67
84
|
|
|
68
|
-
A cycle between
|
|
69
|
-
|
|
70
|
-
- A group cycle is allowed only when every cross-group member edge in it is listed by an exception. The command then prints one `excepted` line with the groups, the exception id, the ruling link, the allowed edges and the reason, and the cycle does not fail. If one edge is not listed, the cycle fails as before. The message ends with the edges that are not listed, and the machine-readable `edges` of the finding stay the full list of edges in the cycle. A new member edge between the same groups, which no exception lists, therefore always makes the cycle fail.
|
|
71
|
-
- Each listed edge must appear in a group cycle, whether or not that cycle is allowed. An exception with an edge that does not appear (the edge was removed, the cycle is gone, or the edge is not in the cycle) is an `unused-group-cycle-exception` finding and exits 1. The `edges` of that finding are the edges that did not appear. This is judged only when the checked tree is the runner repository itself (both roots resolve to the same directory). When the checked tree is another tree (`OMNE_RUNNER_ROOT` points elsewhere), exceptions still allow the cycles they list, but an unused exception is not reported: the exception is recorded in the runner tree, so the cycles of the checked tree cannot show that it is out of date. `omne-deps`, `omne-loop-status` and the stop hook use the same judgement.
|
|
72
|
-
- Exceptions do not apply to cycles between members, to file cycles, or to other rules.
|
|
73
|
-
- When at least one group cycle is allowed, the last line of the summary ends with `<n> 个组环按具名例外放行` (`<n>` group cycles allowed by named exceptions).
|
|
74
|
-
- The hard lines of `omne-loop-status` and of the stop hook read the same exceptions. An excepted group cycle is not a hard line. The status lists it under the cycle line and keeps it in `hardLines.exceptedCycles` of `status.json`. An unused exception is a cycle hard line. When the `constraints.json` of the runner is not valid, `omne-loop-status` exits 2 as a tool error.
|
|
75
|
-
- `omne-metrics` and the architecture report do not read exceptions. They still list an excepted group cycle as a cycle.
|
|
85
|
+
A cycle between members makes `omne-deps` exit 1 and is a hard line of `omne-loop-status`. A cycle that exists only at the level of groups, with no cycle between members, is not a finding.
|
|
76
86
|
|
|
77
87
|
## Contract API snapshots
|
|
78
88
|
|
|
@@ -91,7 +101,7 @@ The class is a whitelist gate. Differences fall into two buckets. Any difference
|
|
|
91
101
|
|
|
92
102
|
The tool does not use API Extractor, because API Extractor does not analyze ambient declarations. It drops every `declare module` and `declare global` augmentation, and the public surface of 8 of the 27 contract members contains such augmentations.
|
|
93
103
|
|
|
94
|
-
The `contractApi` configuration section has two keys. `members` is the path of the
|
|
104
|
+
The `contractApi` configuration section has two keys. `members` is the path of the contract member table. `snapshot` is the snapshot path template. It ends with `.md` and contains `{member}` or `{package}`. Any other key, a missing key or a bad value is an error.
|
|
95
105
|
|
|
96
106
|
`review` means that a person must decide. It includes changes that break the writer, the reader or both. It also includes changes that the additive-change table allows but that are outside the whitelist. Examples are a new member of a union that the contract declares open, and a new default for a type parameter. `review` is not a level for the "契约变化" section of a PR. A person decides that level (none, additive or breaking) from the additive-change table in `docs/engineering/integration.md`.
|
|
97
107
|
|
|
@@ -104,12 +114,25 @@ A card that changes the public surface of a contract member runs `--write` in th
|
|
|
104
114
|
The Stop hook recalculates its baseline on each invocation. With a task context it uses `taskBase`. Without one it uses the nearest merge base among `primaryBranch` and the active tracks in `integration-policy.json`. See the Chinese README section "收工钩子" for the exact rules.
|
|
105
115
|
The global architecture reader resolves that base to a fixed commit and batches its selected source and intent blobs.
|
|
106
116
|
They use byte lengths for UTF-8 content and preserve literal paths, empty files and read failures.
|
|
107
|
-
|
|
117
|
+
Source ownership uses the longest member prefix and one inventory traversal.
|
|
118
|
+
The base side of the architecture readings (the base constraints, the actual extraction and its deviation rows) is calculated once per commit and stored in `hook-baseline/` in the loop directory. Later stops only read it.
|
|
119
|
+
The cache key is the base commit, the `sensors.architecture` section of the configuration, a digest of the tool code (every file in the package code directory, and the TypeScript version) and the storage format version. When the key does not match or the file is damaged, the hook calculates the base side again and replaces the file. It never uses an old reading for a different key.
|
|
120
|
+
The hook prepares the base side first. Thus, when the first measurement on a new base goes over the time limit, the base side is stored, and the warning says that the next stop will not calculate it again.
|
|
121
|
+
The working-tree side is calculated on each stop.
|
|
122
|
+
The dependency findings use only the edges of the changed files (`src/loop/hook-graph.ts`). The hook does not calculate the full working-tree dependency graph. An edge belongs to the file that has the import, so a new edge can only come from a changed file, and each new cycle or direction violation contains a new edge.
|
|
123
|
+
The hook reads the per-commit dependency graph of the base (the same cache in `<git-common-dir>/omne-dep-graph/` that `loop:status` uses). It runs dependency-cruiser only on the changed source files that still exist, with the rules and resolution options of `lint:deps`, and it does not follow their import targets. Then it replaces the dependencies and violations of those files in the base graph. It calculates the member edges, member cycles and group cycles again on the result. The time follows the number of changed files, not the size of the repository.
|
|
124
|
+
When the base graph is not in its cache, the hook calculates it first, as it does for the base side of the architecture readings. When that measurement goes over the time limit, the warning says that the base readings are stored and that the next stop will not calculate them again.
|
|
125
|
+
When the resolution configuration changed, the hook does not measure the dependency findings. It adds only the line "本次改了解析配置,依赖项看 pnpm run lint:deps". It does not fall back to the full graph. The resolution configuration changed when the content of the root `.dependency-cruiser.cjs` or a root `tsconfig*.json` changed, or when `name`, `exports`, `main`, `module`, `types`, `typings` or `imports` changed in the `package.json` of a member. The hook compares only files that exist on both sides. `pnpm-lock.yaml`, member tsconfig files and other manifest fields do not count.
|
|
126
|
+
Two cases are not covered: a file cycle inside one member (the base graph keeps only cross-member dependencies), and an old edge from an unchanged file to a deleted file. `pnpm run lint:deps` finds both.
|
|
127
|
+
The measurement runs in a child process. At the time limit the hook stops that process together with the processes it started (dependency-cruiser), and then it shows the user a warning. See the Chinese README for the measured times.
|
|
108
128
|
|
|
109
129
|
Synchronizing the primary branch can remove delivered changes from the current difference.
|
|
110
130
|
For a task-wide report, run `pnpm run loop:status --base <task-start-commit>` with a fixed task anchor.
|
|
111
131
|
That explicit base does not change the automatic hook's base. The internal 40-second limit and host error protocol remain unchanged.
|
|
112
132
|
|
|
133
|
+
The hook reports only the findings that are new or worse since the last reading of the same worktree and branch. It keeps that reading in `hook-readings.json` in the loop directory. When the running script is not in the measured checkout and `OMNE_RUNNER_ROOT` is not set, the hook does not measure. It shows the user a warning that it cannot measure, because the tool in the other checkout can be out of date.
|
|
134
|
+
The host command runs only the script of the worktree where the session is. It does not use the script of another checkout. When the worktree does not have the script, the command exits 0 and writes nothing. When the worktree does not have its dependencies installed, the script shows the user a warning that it cannot measure.
|
|
135
|
+
|
|
113
136
|
## Actual assembly observations
|
|
114
137
|
|
|
115
138
|
The clean loop reads complete current and BASE sources through `sensors.architecture`.
|
|
@@ -147,7 +170,8 @@ The artifact contains a read-only list of fixed decisions in `src/acceptance/his
|
|
|
147
170
|
Each entry covers one commit and one protected path. A commit with more protected paths has one entry for each path.
|
|
148
171
|
The [D010 decision](https://github.com/nemori-ai/omne-harness-lite/issues/638#issuecomment-6367449357) covers commit `48ad37d292796326d65055a75e8a1fde44fe4233` and `packages/agent/agent/acceptance/README.md`.
|
|
149
172
|
The [#769 decision](https://github.com/nemori-ai/omne-harness-lite/issues/769#issuecomment-6411908205) covers 27 paths in commits `19f457a15`, `9f3967cc5`, `69bdedfab`, `837d333fd`, `14b0fcfcb` and `06acd53ca`.
|
|
150
|
-
Without a task context, the lock compares a merge commit with each parent (
|
|
173
|
+
Without a task context, the lock compares a merge commit with each parent (`-m`) and lists each path that differs from one parent. With a task context it uses `--cc`, which lists only paths that differ from all parents. A clean merge then lists no paths. The six #769 commits contain four such merges.
|
|
174
|
+
One `git log --name-only` call reads the paths of all commits in the range. It lists the same paths as one `git diff-tree --no-commit-id --name-only --no-renames -r` call for each commit. The call fixes `log.diffMerges=separate`, so user configuration cannot change `-m` to the first parent only. It fixes `log.showRoot=false`, so a root commit lists no paths, as `diff-tree` does without `--root`. It also adds `--no-show-signature`.
|
|
151
175
|
By registration convention, a merge entry names the one parent where the path changed. The tool does not check this convention. It checks only that the named parent is one of the parents of the commit.
|
|
152
176
|
The tool checks real Git objects, that the named parent is a parent of the commit, exact blobs, and all bytes from `git diff --no-ext-diff --no-textconv --no-color --binary -U3 --src-prefix=a/ --dst-prefix=b/ --text`.
|
|
153
177
|
For a path that does not exist on one side, the blob is the Git null object ID (40 zeros), as `git diff --raw` shows it. The tool then checks that the tree has no such path.
|
package/README_ZH.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
- [dev-flow](../dev-flow/README_ZH.md):开工准入、任务绑定、Issue 与看板读取、包模板。
|
|
10
10
|
- [product-checks](../product-checks/README_ZH.md):本仓库的产品规则、验收覆盖声明与场景状态。
|
|
11
|
-
- [test-runner](../test-runner/README_ZH.md)
|
|
11
|
+
- [test-runner](../test-runner/README_ZH.md):影响面计划、成员测试与耗时账本;差分变异经 [pqw-adapter](../pqw-adapter/README_ZH.md)。
|
|
12
12
|
|
|
13
13
|
## 仓库根与配置
|
|
14
14
|
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
| 命令 | 源码入口 | 作用 |
|
|
31
31
|
| --- | --- | --- |
|
|
32
|
-
| `omne-deps` | `src/deps/cli.ts` | 依赖规则、`constraints.json`
|
|
32
|
+
| `omne-deps` | `src/deps/cli.ts` | 依赖规则、`constraints.json` 的方向行,与成员之间的环 |
|
|
33
33
|
| `omne-declarations` | `src/declarations/cli.ts` | 用 TypeScript 6 读成员 dist 里的声明 |
|
|
34
34
|
| `omne-contract-api` | `src/declarations/api-cli.ts` | 契约成员的 API 快照:写、核对与相对基线的粗分类 |
|
|
35
35
|
| `omne-metrics` | `src/metrics/cli.ts` | 结构度量与审讯页 |
|
|
@@ -61,7 +61,7 @@ pnpm --filter @omne-harness/repo-toolchain test
|
|
|
61
61
|
|
|
62
62
|
## Git 环境隔离
|
|
63
63
|
|
|
64
|
-
显式仓库的 Git 子进程由 [git-environment.ts](src/core/git-environment.ts) 隔离八项仓库定位变量。认证、Git 配置、OMNE runner/subject 与测试控制参数继续继承。Vitest 在加载测试文件前另清两个 OMNE root,防止普通 fixture 读写外部仓库;污染回归在被测入口显式注入环境。持续验证见 [repository-environment.spec.ts](tests/repository-environment.spec.ts)
|
|
64
|
+
显式仓库的 Git 子进程由 [git-environment.ts](src/core/git-environment.ts) 隔离八项仓库定位变量。认证、Git 配置、OMNE runner/subject 与测试控制参数继续继承。Vitest 在加载测试文件前另清两个 OMNE root,防止普通 fixture 读写外部仓库;污染回归在被测入口显式注入环境。持续验证见 [repository-environment.spec.ts](tests/repository-environment.spec.ts)。
|
|
65
65
|
|
|
66
66
|
## 依赖图与依赖规则
|
|
67
67
|
|
|
@@ -69,15 +69,37 @@ pnpm --filter @omne-harness/repo-toolchain test
|
|
|
69
69
|
|
|
70
70
|
- 规则:无法解析的导入、文件级运行时循环、legacy 引用,以及按[产品包组织](../../docs/package-organization.md#依赖方向与cordis集成)与[系统分层](../../docs/architecture/layers-and-dependencies.md#依赖关系与禁止方向)写成成员路径的方向规则(SDK 与 server-entry 互不导入、公开契约不依赖两端实现、业务不依赖 SDK 与装配入口、common 与 util 不依赖领域成员、产品包不依赖应用与工具)。每条规则的 `comment` 指回出处。要按角色判断的规则(契约不依赖提供者等)还没有机读的角色,没有写。
|
|
71
71
|
- 方向行:`docs/architecture/constraints.json` schema 3 的 `directions`,格式与校验见[符合性契约](src/arch/CONFORMANCE.md#方向行);`omne-deps` 怎样用它见下面[依赖方向](#依赖方向)一节。
|
|
72
|
-
-
|
|
73
|
-
- 成员边:产品源码(不含测试)解析到另一个成员的依赖,类型导入也算。成员与组之间的环由这些边算出。导入处的行号按说明符在文件里第一次出现的位置找。图里另保留成员里 dependency-cruiser 走到的模块清单(`modules`)与跨成员的文件级依赖事实(`dependencies`,含测试与 `src` 下的 testing 入口,不含 Node 内建模块),方向行的判定与架构符合性报告的方向行都只从这两项判断,不另解析导入。
|
|
72
|
+
- 成员边:产品源码(不含测试)解析到另一个成员的依赖,类型导入也算。成员之间的环由这些边算出,有环即失败。只在组的层面成环、成员之间不成环的不算:一个组里的不同成员可以分别依赖另一个组。导入处的行号按说明符在文件里第一次出现的位置找。图里另保留成员里 dependency-cruiser 走到的模块清单(`modules`)与跨成员的文件级依赖事实(`dependencies`,含测试与 `src` 下的 testing 入口,不含 Node 内建模块),方向行的判定与架构符合性报告的方向行都只从这两项判断,不另解析导入。
|
|
74
73
|
- 工作树的图不含被 Git 忽略且未跟踪的目录里的模块与它们的违规(本地产物,理由同[实际架构](#全局实际架构视图)的成员规则);不在 Git 仓库里的目录没有忽略规则,照常出图。
|
|
75
74
|
- 规则与解析选项(`tsconfig.base.json` 的 `source` 条件)只从运行检查器的仓库读,被检查的检出改不了。
|
|
76
75
|
- 基线图:把那个提交的源码导出到 git 公共目录下的临时树,按成员包名补上 `node_modules/@omne-harness/*` 链接后跑;结果按提交、规则文件摘要与图的格式版本缓存在 `<git-common-dir>/omne-dep-graph/`,同一基线只算一次,不写工作树。
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
- 临时树叫 `tree-<提交>-<进程号>`,算完就删;Windows 上刚解开的文件可能还被别的程序占着,删除时重试几次,仍删不掉只在标准错误报告,不改变图的结果。运行被强行结束(任务超时、关掉终端、杀进程树)时来不及删,所以每次算基线图开始时清掉进程已不在、且 10 分钟没动过的旧树;活着的进程的树不动。宽限期是为同一个 git 目录被 WSL 里的运行共用的情形:那边的进程这里看不见。
|
|
77
|
+
- 工作树的图:按指纹缓存在同一目录的 `working-<指纹>.json`。指纹(`workingGraphFingerprint`)覆盖所有能改变图的输入:
|
|
78
|
+
- 图的格式版本与 dependency-cruiser 的版本。
|
|
79
|
+
- 规则文件(原文与 require 后的结果)、`tsconfig.base.json` 连同 `extends` 链。
|
|
80
|
+
- HEAD 提交。
|
|
81
|
+
- 全部未提交与未跟踪文件的路径与内容。不按扫描根过滤,因为 dependency-cruiser 会解析扫描根以外的导入目标。
|
|
82
|
+
- 被忽略的路径。同样不按扫描根过滤:目录只记存在与否,单个文件记内容。
|
|
83
|
+
- 被忽略目录的判定结果。
|
|
84
|
+
- `pnpm-lock.yaml` 与 `node_modules/.modules.yaml` 的内容。
|
|
85
|
+
- 当前运行的出图代码(`src/deps/graph.ts`)的内容摘要:钉住的发行版与源码版在同一个头上不会互相命中。基线图的缓存键同样带它。它引用的其他模块变了,仍靠加图格式版本兜底。
|
|
86
|
+
|
|
87
|
+
命中时不起 dependency-cruiser,读到的图与重算的逐字节相同。未命中照常算,算完先写临时名再改名,只留最近 10 份。
|
|
88
|
+
- 缓存读不到、JSON 坏、格式或指纹对不上、写不进都按未命中,既不让检查失败也不让它放行。
|
|
89
|
+
- `OMNE_DEP_GRAPH_CACHE=0` 关掉缓存:不读不写,行为与没有缓存时相同。
|
|
90
|
+
- `OMNE_ADMISSION=1` 时不读缓存,照常计算并写入。不设或空串为非准入,其他值报错,与测试运行器的规则相同。
|
|
91
|
+
- 算完图后复核指纹。运行期间输入变了就不写缓存;stderr 是终端时提示一行。
|
|
92
|
+
- stderr 是终端时打一行命中与否;管道里不打,输出与没有缓存时相同。
|
|
93
|
+
- 不在 git 仓库里或没有提交的树没有指纹,照常出图不缓存。
|
|
94
|
+
- 被忽略的目录只记存在与否,所以写缓存时另记一份复核清单:不在被忽略目录里的模块的导入,且解析到被忽略目录里的文件(不含 `node_modules`,它由锁文件与 `.modules.yaml` 的内容兜住)。清单记下每个文件的内容摘要。命中前逐个核对,文件删了或内容变了就当未命中重算。
|
|
95
|
+
|
|
96
|
+
命中不能声称的:复核清单只记已经解析到的文件。原来解析不到的导入,之后在被忽略的目录里出现了文件,指纹不变,缓存可能仍报出旧的失败,不会放行。被忽略的目录里新增一个文件、让已有的导入改为解析到它时,缓存也看不出。
|
|
97
|
+
|
|
98
|
+
做法借鉴 ub-mode 列出的 crapper 复用已有覆盖报告(`--use-existing-coverage`)与 mutator 的差分快照:先按输入指纹判没变,没变就不重算。
|
|
99
|
+
- 耗时(Windows 宿主,24 核):全仓一次 dependency-cruiser 约 14 秒,工作树指纹约 0.7 秒,`lint:deps` 命中缓存约 1.2 秒;基线命中缓存约 10 毫秒。
|
|
100
|
+
- 回路状态的硬线是依赖违规与环;方向命中只让 `lint:deps` 退出 1,回路里只报告。
|
|
101
|
+
|
|
102
|
+
自测:`tests/deps-graph.spec.ts`、`tests/deps-graph-cache.spec.ts`(指纹逐类失效,含扫描根之外的未提交文件与被忽略的路径;命中、坏文件、开关、留份、算图期间输入变了不写缓存)、`tests/deps-graph-trees.spec.ts`(过期临时树的清理)、`tests/direction-rules.spec.ts`、`tests/deps-cycles.spec.ts`(成员成环失败;只在组的层面成环不是发现);回路金丝雀种了一处 `shared-stays-pure` 违规与一对成环的成员。
|
|
81
103
|
|
|
82
104
|
### 依赖方向
|
|
83
105
|
|
|
@@ -90,17 +112,6 @@ pnpm --filter @omne-harness/repo-toolchain test
|
|
|
90
112
|
- 没有方向行:运行检查器的仓库没有 `constraints.json` 时不检查方向,写「runner 没有 docs/architecture/constraints.json,未检查」,退出码只由其他发现决定;文件是 schema 1、2,或 schema 3 缺省 `directions`,写「没有方向行」。
|
|
91
113
|
- 退出 2:`constraints.json` 解析失败、校验失败、来源核对失败,或 `docs/architecture/constraints.json` 与 `.meta_harness/design/architecture/constraints.json` 两份并存。先读它再运行 dependency-cruiser,所以文件坏了不出依赖图。
|
|
92
114
|
|
|
93
|
-
### 组环例外
|
|
94
|
-
|
|
95
|
-
组之间成环默认失败。负责人裁定某条具体的依赖链在架构上成立时,在运行检查器的仓库的 `constraints.json` 里登记一条 `groupCycleExceptions`,写明成员边(`from`、`to` 是成员路径)、裁定链接和一句理由。例外只放行登记的那几条边。例外与方向行一样只从运行检查器的仓库读,被检查的树登记的例外不生效。例外从 repo-toolchain 0.0.16 起执行。
|
|
96
|
-
|
|
97
|
-
- 放行:一个组环的每一条跨组成员边都登记了,`omne-deps` 才放行它,另写一行 `excepted 组环 <组>、<组> 按例外 <id>(裁定 <链接>)放行 <from> → <to>、…:<理由>`。环上有一条边没登记,就照常报 `组之间成环` 并失败,消息末尾列出没登记的边;机读的 `edges` 仍是环上的全部边。因此两个组之间以后新增的任何没有登记的成员边,都会让组环失败。
|
|
98
|
-
- 没用上:登记的边必须出现在某个组环里,不论那个组环最后是否放行。边被删、组环已消失或边不在环上时,这条例外报一条 `unused-group-cycle-exception`,写明 id、没用上的边和裁定链接,并退出 1。这条发现的机读 `edges` 是没用上的边。要删掉或改写这条例外。只有被检树就是运行检查器的仓库自己时才判这一条。跨树检查(`OMNE_RUNNER_ROOT` 指向另一个仓库)时,例外照常放行登记的组环,但不判没用上:登记它的是 runner 的树,被检树的组环说明不了它有没有过期。`omne-deps`、回路状态与收工钩子的判断一致。
|
|
99
|
-
- 成员环:成员之间的环不受例外影响,照常失败。文件环与其他规则也一样。
|
|
100
|
-
- 汇总行:有放行的组环时,末行写「<n> 个组环按具名例外放行」。
|
|
101
|
-
- 回路状态:硬线读同一份例外。放行的组环不算硬线,在 `status.md` 硬线一段的「环」下面列出例外、裁定链接与放行的边,在 `status.json` 的 `hardLines.exceptedCycles` 里保留。没用上的例外算进「环」这条硬线。runner 的 `constraints.json` 坏了时,回路状态按工具错误退出 2。收工钩子的硬线同样按例外判。
|
|
102
|
-
- 结构度量与实际架构的报告不读例外:它们照旧把放行的组环列为环。
|
|
103
|
-
|
|
104
115
|
## 提交署名
|
|
105
116
|
|
|
106
117
|
`commit-attribution`(`src/commits.ts`)随 `pnpm run lint:rules` 执行,有违反即退出 1。它查的不是源码,
|
|
@@ -152,7 +163,8 @@ Loop 的 Markdown 同时显示原始违规和批准决定;其他硬线照常
|
|
|
152
163
|
固定决定编进 `src/acceptance/historical-approvals.data.ts` 的只读列表(核对器 `src/acceptance/historical-approvals.ts` 只读这份列表),每条对应一个提交里的一个受保护路径;一个提交改了几个受保护路径,就登记几条。
|
|
153
164
|
[D010 的决定](https://github.com/nemori-ai/omne-harness-lite/issues/638#issuecomment-6367449357)批准提交 `48ad37d292796326d65055a75e8a1fde44fe4233` 中的 `packages/agent/agent/acceptance/README.md` 改动。
|
|
154
165
|
[#769 的决定](https://github.com/nemori-ai/omne-harness-lite/issues/769#issuecomment-6411908205)批准提交 `19f457a15`、`9f3967cc5`、`69bdedfab`、`837d333fd`、`14b0fcfcb`、`06acd53ca` 中的 27 个路径改动。
|
|
155
|
-
|
|
166
|
+
没有任务上下文时,验收锁把合并提交与每个父提交分别比较(`-m`),与任一父提交不同的路径都列出。有任务上下文时它用 `--cc`,只列与所有父提交都不同的路径,干净合并因此不列路径。#769 的六个提交里有四个是这样的合并。
|
|
167
|
+
每个提交改到的路径由一次 `git log --name-only` 读出,列出的路径与逐个提交运行 `git diff-tree --no-commit-id --name-only --no-renames -r` 相同:调用固定 `log.diffMerges=separate`(用户配置不能把 `-m` 改成只比第一个父提交)与 `log.showRoot=false`(根提交不列路径,与 `diff-tree` 不加 `--root` 相同),并加 `--no-show-signature`。
|
|
156
168
|
登记约定是:合并提交的条目写该路径有变化的那一个父提交。工具不核对这条约定,只核对所写父提交是该提交的父提交之一。
|
|
157
169
|
工具读取真实 Git 对象,核对完整提交、所写父提交确是该提交的父提交、受保护路径、旧新 blob 和完整二进制 diff 的 SHA-256。某一侧没有这个路径时,blob 记为 Git 的空对象号(40 个 0,与 `git diff --raw` 的写法相同),工具核对该侧的树里确实没有这个路径。该 diff 使用 `git diff --no-ext-diff --no-textconv --no-color --binary -U3 --src-prefix=a/ --dst-prefix=b/ --text`。
|
|
158
170
|
调用固定 `core.abbrev=8`、`diff.noprefix=false`、`diff.mnemonicPrefix=false`、`diff.algorithm=myers`、`diff.indentHeuristic=true`、`diff.context=3`、`diff.interHunkContext=0`、`diff.suppressBlankEmpty=false`、`diff.srcPrefix=a/`、`diff.dstPrefix=b/`、`core.attributesFile=/dev/null` 与 `attr.tree`(空树),从环境中去掉 `GIT_DIFF_OPTS` 与 `GIT_ATTR_SOURCE`,并设 `GIT_ATTR_NOSYSTEM=1`。仓库大小与这些配置不会改变字节。
|
|
@@ -268,10 +280,20 @@ architecture 报告的函数变化和关系变化都用精确 BASE;metrics 报
|
|
|
268
280
|
pnpm run metrics # 全仓:实际架构、圈复杂度、依赖图、依赖方向与环
|
|
269
281
|
pnpm run metrics --base <基线提交或分支> # 另标出基线以来变更的成员、函数、导入与提交形状
|
|
270
282
|
omne-metrics --plan <计划文件> --coverage # 再对计划里要跑测试的成员逐个跑测试,取覆盖率并合成 CRAP(先构建)
|
|
283
|
+
omne-metrics --plan <计划文件> --coverage --coverage-parallel 3x5 # 覆盖率跨成员并行:同时 3 个成员,每个至多 5 个工作进程
|
|
271
284
|
```
|
|
272
285
|
|
|
273
286
|
计划文件由 test-runner 的 `plan --json` 写出,准入检查用的也是它(见 [test-runner](../test-runner/README_ZH.md))。给 `--plan` 时,基线与合并点也取自计划,不能再给 `--base`;计划文件复制到产物目录的 `plan.json`。计划算的不是当前提交时,工具报错退出;工作树绑定了任务上下文时,计划的基线还要与上下文固定的基线一致。`--coverage` 必须带 `--plan`。算完计划后工作树又改了计划外的成员时,带覆盖率的运行报错退出,要求重算计划。改过的文件按最长的成员目录前缀归到成员;成员是 `pnpm-workspace.yaml` 的成员模式匹配到、且 `package.json` 有字符串 `name` 的目录。组根文件(`packages/<组>/README.md`、`packages/<组>/docs/**`)没有成员前缀,不算成员,改它们不触发这项检查。
|
|
274
287
|
|
|
288
|
+
覆盖率缺省逐个成员串行,vitest 的工作进程数由 vitest 自己按核数定。给了 `--coverage-parallel <M>x<W>`(或环境变量 `OMNE_METRICS_COVERAGE_PARALLEL`,参数优先;只在带 `--coverage` 时生效)就跨成员并行:同时至多 M 个成员,每个成员的 vitest 加 `--maxWorkers=W`。本工具不推预算。`pnpm run metrics --coverage` 经 `scripts/metrics.sh` 在占到运行名额后向 test-runner 要并发度(`coverage-parallel`,两数之积不超过本机的工作进程预算,`OMNE_WORKER_BUDGET` 可覆盖),再经环境变量交下来;不认这个变量的旧版本照旧串行。调用方已设变量或给了参数时,脚本不另算。并行时:
|
|
289
|
+
|
|
290
|
+
- 预计最久的成员先开始。预计耗时取产物目录上级(缺省为主检出的 `tmp/metrics/`)与这次 `--out` 上级里历次 `metrics.json` 的 `meta.coverageSeconds`,同一成员取最新一份的正数;没有记录的按测试文件数,乘上有记录的成员平均每个文件的秒数。顺序只影响墙钟,不影响读数。
|
|
291
|
+
- 各成员的日志、报告目录与退出码与串行时相同,结果按成员原来的顺序合并,不随完成先后变。进度在每个成员跑完时打一行。
|
|
292
|
+
- 静态度量(依赖图、实际架构、符合性)与覆盖率同时进行,它们只读工作树,不读覆盖率。串行时仍先跑完覆盖率。
|
|
293
|
+
- 一个成员起不来时不再开新成员,等已开始的结束,再报错退出。
|
|
294
|
+
|
|
295
|
+
这里借鉴了 crapper([unclebob/ub-mode](https://github.com/unclebob/ub-mode/tree/57a8bdd) 列出的 CRAP 工具)的两种做法:按核数并行,以及在覆盖报告已经存在时复用它(`--use-existing-coverage`)。只采用了前一种。复用要能判定已有报告的输入与这次相同:成员与它的工作区依赖的 `dist/`、测试、配置与安装状态都不在提交里,同一提交上也可能不同。本工具判定不了,所以不复用,每次重跑。
|
|
296
|
+
|
|
275
297
|
本工具只读计划文件的四栏:`head`、`base.ref`、`base.mergeBase` 与 `plan.test`(成员目录的数组)。这四栏是本包的输入约定,现在由 test-runner 的 `plan --json` 写出。
|
|
276
298
|
|
|
277
299
|
产物默认落**主检出**的 `tmp/metrics/<提交短号>[-dirty]/`(在工作树里跑也落主检出,工作树退役不带走;`--out` 或环境变量 `OMNE_METRICS_OUT` 可改):
|
|
@@ -285,7 +307,7 @@ omne-metrics --plan <计划文件> --coverage # 再对计划里要跑测试的
|
|
|
285
307
|
| `actual.json` | N1 完整实际架构数据及精确两版差分 |
|
|
286
308
|
| `architecture.json` | 总览、关系与来源的派生浏览投影;与旧 graph.json 分开 |
|
|
287
309
|
| `plan.json` | 给 `--plan` 时复制的计划文件 |
|
|
288
|
-
| `coverage/` | 开了覆盖率时各成员的原始 `<成员>/coverage-final.json` 与测试输出 `<成员>.vitest.log`;每个成员的耗时与退出码另记在 `metrics.json` 的 `meta`
|
|
310
|
+
| `coverage/` | 开了覆盖率时各成员的原始 `<成员>/coverage-final.json` 与测试输出 `<成员>.vitest.log`;每个成员的耗时与退出码另记在 `metrics.json` 的 `meta` 里,运行时逐个打到标准错误;并行时的耗时含与别的成员争抢 CPU 的时间 |
|
|
289
311
|
|
|
290
312
|
审讯页的网址后带成员路径可直接定位,例如 `review.html#packages/model/model-request-runtime-local`。
|
|
291
313
|
|
|
@@ -335,10 +357,10 @@ omne-metrics --plan <计划文件> --coverage # 再对计划里要跑测试的
|
|
|
335
357
|
pnpm run loop:status # 全仓现状
|
|
336
358
|
pnpm run loop:status --base <任务基线> # 另列这次变更里要解释的红项,并核验收锁
|
|
337
359
|
pnpm run loop:status --snapshot # 干净的工作树上追加一条趋势快照
|
|
338
|
-
pnpm run loop:status --base <基线> --strict --out <目录> # 严格模式,
|
|
360
|
+
pnpm run loop:status --base <基线> --strict --out <目录> # 严格模式,mainline 提升 main 时的整仓健康读数
|
|
339
361
|
```
|
|
340
362
|
|
|
341
|
-
**除硬线外一切只报告。**退出码 1 只在硬线被破时:依赖违规或环(与 `pnpm run metrics`、`lint:deps` 读[同一张依赖图](#依赖图与依赖规则);无法解析的导入归 `lint:deps
|
|
363
|
+
**除硬线外一切只报告。**退出码 1 只在硬线被破时:依赖违规或环(与 `pnpm run metrics`、`lint:deps` 读[同一张依赖图](#依赖图与依赖规则);无法解析的导入归 `lint:deps`,不算硬线),
|
|
342
364
|
或给了 `--base` 且[验收锁](#验收锁)被破,或严格模式下有开着的传感器没数据;
|
|
343
365
|
2 是工具自己出错(参数、配置、git);其余报告项再多也是 0。
|
|
344
366
|
|
|
@@ -346,9 +368,9 @@ pnpm run loop:status --base <基线> --strict --out <目录> # 严格模式,
|
|
|
346
368
|
有哪个报「没数据」,「硬线」一段列出是哪几个、原因是什么,退出 1;配置里关掉的不算,照旧写明是关掉的。
|
|
347
369
|
对照表那一项没有开关、也不进指标,不在此列。「没有基线快照,与基线比未判」是趋势的事,不算传感器没数据。
|
|
348
370
|
它要求给 `--base` 与 `--out`(缺了按用法错退出 2),草稿写进 `--out` 目录下的 `proposals/`,不写趋势快照(与 `--snapshot` 同用也是用法错)——
|
|
349
|
-
|
|
371
|
+
回路目录里一个字节都不动。它不在 `pnpm run check` 里:mainline 提升 main 的 PR 开出后跑一次,摘要贴在提升 PR 上,只报告不挡(做法归 `omne-card` 技能的「提升与发行」)。
|
|
350
372
|
|
|
351
|
-
CLI 的范围只有 `all` 和 `engineering`,默认 `all`;工程范围必须与 strict
|
|
373
|
+
CLI 的范围只有 `all` 和 `engineering`,默认 `all`;工程范围必须与 strict 同用。提升 main 时的整仓健康读数不传范围,使用默认 `all`。
|
|
352
374
|
工具复用当前传感器的源码清单,并枚举固定 targetBase、实际 merge-base、每个任务 taskBase 的 Git 树,按同一规则统计源码和测试。相同提交去重。没有 task context 的仓库使用有效显式 base 及其 merge-base。
|
|
353
375
|
只有当前与全部基线的两类计数均为零,duplication、assertions 启用但无数据时才列入 `hardLines.sensors.notApplicable`,原因码为 `engineering-without-product-inputs`。
|
|
354
376
|
`status.json` 的 `scope.evidence` 保存当前计数和各基线的精确提交、计数。原始 `sensors` 仍是 no-data;终端与 Markdown 点名工程范围不适用。关闭项仍列 `off`,其他启用的无数据项仍列 `silent` 并失败。
|
|
@@ -370,9 +392,9 @@ CLI 的范围只有 `all` 和 `engineering`,默认 `all`;工程范围必须
|
|
|
370
392
|
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
371
393
|
| `status/<提交短号>[-dirty]/status.md` | 与终端打印相同的文字,分五段:抬头(含用的哪条基线快照)、硬线、各项指标的带位、要解释的红项、超预算的成员(含比基线变差的成员)与对照表条数;`--out` 可改目录 |
|
|
372
394
|
| `status/…/status.json` | 全量:每个传感器的原始结果(有数据/没数据及原因)、每个成员的四项预算、带位与各项与基线比的结果、要解释的红项全集(函数一类每条带与基线比的结果,没变差的另列在 `functionsNotWorse`) |
|
|
373
|
-
| `proposals/<成员路径斜杠换成 ->.md` | 超预算成员的清理草稿,同一成员覆盖旧稿;六个固定章节与[派发模板](
|
|
395
|
+
| `proposals/<成员路径斜杠换成 ->.md` | 超预算成员的清理草稿,同一成员覆盖旧稿;六个固定章节与[派发模板](../../docs/clean-loop-cleanup-task.md)同名同序(常量 `CLEANUP_SECTIONS`) |
|
|
374
396
|
| `trend.jsonl` | 趋势快照,一行一条:提交、各指标的值与带位、各成员的预算值与带位 |
|
|
375
|
-
| `hook-
|
|
397
|
+
| `hook-readings.json`、`hook.log` | [收工钩子](#收工钩子)每棵工作树、每条分支上一次量到的读数(类别、位置与函数的圈复杂度),与它自己出错的原因,一行一次 |
|
|
376
398
|
|
|
377
399
|
**三条带**:每个指标与每项成员预算都有提醒线、处置线、解除线(数值越大越差,`release ≤ warn ≤ act`)。值到处置线进入处置;
|
|
378
400
|
进入之后要回落到解除线及以下才解除,低于处置线但高于解除线仍是处置,这样一个值在线附近摆动时带位不跟着来回翻。
|
|
@@ -542,7 +564,7 @@ rev 翻动只数改了 `revision:` 行的提交,不看改了什么。自测:
|
|
|
542
564
|
## 收工钩子
|
|
543
565
|
|
|
544
566
|
`src/loop/stop-hook.ts` 由宿主(Claude Code、Codex)在 agent 收工时调用(`Stop` 与 `SubagentStop`),
|
|
545
|
-
|
|
567
|
+
把「这次变更里要解释的红项」里**比上一次新出现或变差的**作为**事实**反馈给 agent:只陈述位置与数值,不写该怎么改。
|
|
546
568
|
宿主配置由 `.meta_harness/agents/hooks/hooks.yaml` 生成,怎么生效、怎么关见那里的 README。
|
|
547
569
|
|
|
548
570
|
标准输入是宿主给的 JSON 对象。要反馈时向标准输出写**恰好一个** `{"decision":"block","reason":"…"}`(两端在这两个事件上都接受这个最小形状,
|
|
@@ -552,7 +574,10 @@ rev 翻动只数改了 `revision:` 行的提交,不看改了什么。自测:
|
|
|
552
574
|
|
|
553
575
|
1. `OMNE_LOOP_HOOK=off` → 什么都不做;输入解析不了、不是对象 → 不反馈。
|
|
554
576
|
2. `stop_hook_active` 为 `true`(这次收工已经因钩子续跑过)→ 不反馈。**每次收工至多拦一次。**
|
|
555
|
-
3. 工作目录取输入的 `cwd`,没有就用进程的当前目录;不在 git 仓库里 →
|
|
577
|
+
3. 工作目录取输入的 `cwd`,没有就用进程的当前目录;不在 git 仓库里 → 不反馈。
|
|
578
|
+
跑的这份脚本不在被量的仓库里(例如手工从别的检出调它),且没给 `OMNE_RUNNER_ROOT` → 不量,按下面「出错」的路径给用户一句「量不了」:
|
|
579
|
+
别的检出里的工具可能落后,量出来的会是旧代码的读数。`loop` 配置(从被量的仓库读)的 `hook.enabled` 为 `false` → 不反馈。
|
|
580
|
+
本检出没装依赖(从脚本所在处解析不到 TypeScript 解析器)→ 不起量读数的线程,同样只给用户一句「量不了」;主线程本来就不加载解析器。
|
|
556
581
|
4. 这次变更(相对下面的基线;已提交、未提交、未跟踪都算)没碰产品源码、全局 `constraints.json` 或其引用的Markdown源 → 不反馈。
|
|
557
582
|
**基线**这样取:
|
|
558
583
|
- 有 task context:取它的 `taskBase`(没有 ownerTask 时取 `targetBase`),不看轨道登记。
|
|
@@ -563,39 +588,56 @@ rev 翻动只数改了 `revision:` 行的提交,不看改了什么。自测:
|
|
|
563
588
|
policy 读不到或读不懂时没有轨道候选,只用 `primaryBranch`(位置按 `origin`)。一个候选也求不出时基线是 `HEAD`,只看未提交的改动。
|
|
564
589
|
- 直接在轨道分支上工作时,HEAD 就是轨道尖端,基线也是它,只看未提交的改动;要看相对 `primaryBranch` 的全部变更,手给 `pnpm run loop:status --base main`。
|
|
565
590
|
5. 量**静态那部分**读数:变更函数里超 alert、且比基线涨了或新出现的(与 `pnpm run loop:status` 同一个判法,见上「要解释的函数与基线比」,基线是这里的合并点;
|
|
566
|
-
反馈的那一行末尾补「原 N
|
|
567
|
-
不跑重复代码(全仓二十多秒)、覆盖率、工作树与 topic
|
|
591
|
+
反馈的那一行末尾补「原 N」「新出现」或拿不准的原因,原来就超线、这次没变差的不反馈)、新增的跨成员依赖、其中稳定依赖不稳定的、改动过的测试文件里没有断言的用例,加依赖违规与环两条硬线。
|
|
592
|
+
不跑重复代码(全仓二十多秒)、覆盖率、工作树与 topic 那几项。量在一个子进程里跑,超过 `hook.timeoutSeconds`(初值 40;宿主那侧另配 60)就放弃,
|
|
593
|
+
连同它起的进程(dependency-cruiser)整组杀掉。不用 worker 线程:线程卡在同步的子进程调用里时,终止它与主进程退出都要等那次调用返回,宿主那侧的时限会先到。
|
|
594
|
+
**依赖项只看改动文件的边**([`hook-graph.ts`](src/loop/hook-graph.ts)),不算整张工作树依赖图:一条依赖边属于发出导入的文件,新增的边只可能出自改过的文件,
|
|
595
|
+
新的环或方向违规一定含一条新边。所以钩子取基线合并点上按提交缓存的依赖图(`<git-common-dir>/omne-dep-graph/`,与 `loop:status` 的基线图同一份),
|
|
596
|
+
只对这次改过且还在的源文件(`packages`、`apps`、`examples`、`tools`、`scripts` 下,含未跟踪的)跑一层 dependency-cruiser,规则与解析选项同 `lint:deps`,
|
|
597
|
+
只往下走这些文件,不走它们的导入目标;再把基线图里这些文件发出的依赖与违规换成现算的。成员边与成员环在换过的依赖上重算,
|
|
598
|
+
新增跨成员依赖、稳定依赖不稳定(成员的不稳定度按换过的成员图算)、dependency-cruiser 的方向规则与全局预期的方向行都读这张图。耗时随改动的文件数走,不随仓库大小走。
|
|
599
|
+
基线图这次没有缓存时现算(全仓一次 dependency-cruiser),与下面 BASE 架构读数一样最先做:这次超时,超时的那句警告同样写明「基线的读数这次已备好存下,下次收工不再重算」。
|
|
600
|
+
**解析配置变了时依赖项不量**,读数里只多一句「本次改了解析配置,依赖项看 pnpm run lint:deps」,不退回全量:没改的文件的导入可能换了落点,基线图里它们的边不再可信。
|
|
601
|
+
算「变了」的是:根上的 `.dependency-cruiser.cjs` 或 `tsconfig*.json` 内容变了,或某个成员的 `package.json` 里 `name`、`exports`、`main`、`module`、`types`、`typings`、`imports` 变了。
|
|
602
|
+
两边都在才比:新加、删掉的不算,导入新成员的文件本身就在改动里。`pnpm-lock.yaml` 只管第三方包,成员里的 tsconfig 不进 dependency-cruiser,版本号、脚本这些字段不影响落点,都不算。
|
|
603
|
+
不覆盖、留给 `pnpm run lint:deps` 的:同一成员里的文件环(基线图只留跨成员的依赖),没改的文件指向已删文件的旧边。
|
|
568
604
|
同时按 BASE 的架构预期判断新增偏离,分别报告全局及原节点预期的语义改动;机械范围见 [CONFORMANCE](src/arch/CONFORMANCE.md)。仅修改预期也可产生反馈,未发布新全局预期的节点继续由原声明传感器消费。
|
|
569
|
-
|
|
570
|
-
|
|
605
|
+
架构读数 BASE 那一侧(BASE 的架构预期、实际抽取、其中的偏离行)按提交算一次,存进回路目录的 `hook-baseline/`([`baseline-cache.ts`](src/loop/baseline-cache.ts)),之后只读。
|
|
606
|
+
键是 BASE 提交、配置里 `sensors.architecture` 那一段、检查器代码的摘要(本包代码目录里每个文件的路径与内容,加 TypeScript 版本)与存储格式版本;
|
|
607
|
+
键对不上、文件坏了都重算并覆盖,不给旧数;最多留 10 份。同一仓库的工作树共用这些文件,读出来的 BASE 坐标换成当前的根。
|
|
608
|
+
这一步在量读数里最先做:BASE 刚换、还没有缓存时,即使这次超时,基线读数也已存下,超时的那句警告会写明「下次收工不再重算」。
|
|
609
|
+
当前工作树那一侧每次都重算,抽取与判偏离共用一个 TypeScript 程序。方向行读运行检查器那棵树的预期与依赖图,不进这份缓存。
|
|
610
|
+
6. 只反馈比上一次新出现或变差的:每条取「类别+位置(路径与函数名、或成员对)」,**不含行号**;函数另记圈复杂度。
|
|
611
|
+
上一次是这棵工作树、这条分支最近一次量出的读数,记在回路目录的 `hook-readings.json`,每棵工作树每条分支一条,最多 `hook.stateLimit`(初值 200)条,超了丢最旧的;读数变了才重写。
|
|
612
|
+
上一次没有的类别与位置算新出现,同一个函数圈复杂度比上一次大算变差;一条都没有 → 不反馈。修掉之后又改回来的,中间那次读数里没有它,改回来再报一次。
|
|
613
|
+
没有上一次(这棵树这条分支第一次量)时全部算新。旧版的 `hook-state.json` 不读。
|
|
571
614
|
7. 反馈的文字列前 `hook.maxItems`(初值 12)条,多的写「另有 N 条」,整段不超过 `hook.maxChars`(初值 4000)个字符;硬线排最前,截断时截掉的是报告项。
|
|
572
615
|
|
|
573
616
|
第 3 步找到仓库之后任何一步抛错或超时 → 不反馈给 agent,往回路目录的 `hook.log` 追加一行原因(写日志失败也吞掉),
|
|
574
617
|
并用 `systemMessage` 给用户一句警告:没量出读数、原因的前 300 个字符、日志在哪。**钩子自己出错从不拦住 agent,但不闷声**——
|
|
575
618
|
不出这一句,「钩子坏了」与「没有红项」在会话里看起来一模一样。
|
|
576
619
|
|
|
577
|
-
**跑的是哪一份脚本**由宿主配置里的命令定(`hooks.yaml
|
|
578
|
-
|
|
579
|
-
2026-10-02 第一次在真实会话里触发时正是栽在这里:脚本在新工作树里加载不了解析器,只记了日志。主检出自己也没装依赖时,结果是上面那句警告。
|
|
620
|
+
**跑的是哪一份脚本**由宿主配置里的命令定(`hooks.yaml`):只跑会话所在那棵工作树自己的,不借别的检出。
|
|
621
|
+
这棵树没有这份脚本(停在旧提交上)→ 命令退出 0,什么都不说;刚 `git worktree add` 出来、还没装依赖的 → 按第 3 步只报「量不了」,装好依赖之后才量。
|
|
580
622
|
|
|
581
623
|
每次调用都重新计算 `git merge-base <primaryBranch> HEAD`,不沿用上一次的基线。
|
|
582
|
-
架构读取先把基线解析成固定 commit,再按该树的 blob ID
|
|
624
|
+
架构读取先把基线解析成固定 commit,再按该树的 blob ID 批量读取文件,不逐文件启动 Git;缓存按这个 commit 存(见第 5 步),不跨提交沿用。
|
|
583
625
|
成员源码与数据文件按最长成员路径前缀分配,文件清单只遍历一次。读取失败仍报错,不以当前工作树补齐旧提交的缺失文件。
|
|
584
626
|
同步主线可能让已交付的改动退出本次差分。需要核对整个任务时,用固定的任务起点运行
|
|
585
627
|
`pnpm run loop:status --base <任务起点commit>`;这个显式基线不改变自动钩子的基线。
|
|
586
628
|
没有输出时还需区分没有新红项、已反馈、递归 Stop 和测量错误,不能仅凭同步发生在先就认定基线损坏。
|
|
587
629
|
|
|
588
|
-
实测(本仓库全量,2026-10
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
加一个分支、反馈一条的 2.5 秒;多出的一次 `git diff -M --name-status` 与每个文件一次 `git show` 合计十几毫秒,再加只解析那几个文件的基线文本。
|
|
630
|
+
实测(本仓库全量,2026-11-10,8 核 Linux):从基线起改过的源文件 75 个、两份基线都已缓存时,依赖项约 2.5 秒(一层 dependency-cruiser 约 2 秒),
|
|
631
|
+
一次收工 23 到 33 秒(1 分钟负载 5 到 17);其余大头是当前工作树的架构抽取(16 到 24 秒,一个 TypeScript 程序加遍历全部产品源码)与度量报告(4 到 7 秒),这两项随仓库大小走。
|
|
632
|
+
再多改 60 个文件(共 135 个)时依赖项约 6 秒,一次收工 23.8 到 28.9 秒(负载 5 到 6)。两份基线都没有缓存的第一次(基线刚换)超过 40 秒,只给用户一句「已备好」的警告,下一次照常给读数。
|
|
592
633
|
|
|
593
|
-
|
|
634
|
+
**不能声称**:反馈过的读数被处理了——它只在新出现或变差时提醒,交代与否由交付说明与接受的人核对;没被反馈等于没有红项——
|
|
594
635
|
没碰产品源码、全局约束或原节点声明,或者钩子关了、出错或超时、`stop_hook_active` 为真时都不反馈,重复代码与覆盖率不在其中,
|
|
595
636
|
**改动落在会话当前目录之外的另一棵工作树里时也不反馈**(hook只量payload的 `cwd` 所在检出;每个写者须显式进入自己的检出,不能只给exec设置workdir就声称宿主cwd已迁移。shell脚本可用当前目录回退,但配置选择依脚本位置;真实host cwd未经验证仍是未覆盖。协作交接见[责任与协作交接](../../docs/engineering/workflow.md#责任与协作交接));宿主真的调用了它——
|
|
596
637
|
生成配置不等于宿主已加载、已信任,要在真实会话里另行核实(Claude Code 一端 2026-10-02 见过一次真实调用;Codex 一端还没有);
|
|
597
638
|
警告一定到了用户眼前——`systemMessage` 怎样显示由宿主定,两端都只按文档核对过,没有在真实会话里看过它显示出来的样子。
|
|
598
|
-
自测:`tests/loop-hook.spec.ts`(判断,外部动作用替身)、`tests/loop-stop-hook.spec.ts
|
|
639
|
+
自测:`tests/loop-hook.spec.ts`(判断,外部动作用替身)、`tests/loop-stop-hook.spec.ts`(入口与线程,用临时仓库与子进程)、
|
|
640
|
+
`tests/loop-hook-graph.spec.ts`(依赖项只换改动文件的边,以整张工作树图对照;解析配置变了只出那一句);
|
|
599
641
|
命令选哪一份脚本由 `.meta_harness/tooling/tests/test_compile_hooks.py` 拿真的工作树跑。
|
|
600
642
|
|
|
601
643
|
## 流程体检页
|
|
@@ -611,7 +653,7 @@ pnpm run loop:health # --out 可改产物目录
|
|
|
611
653
|
| 块 | 内容 | 数据来源 |
|
|
612
654
|
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
613
655
|
| 提交与合并的大小 | `primaryBranch` 沿第一父链最近 `health.commits` 个提交各改了几个文件(合并提交按它对第一父的改动计):中位数、最大值、最大的三个 | `git log --first-parent -m` |
|
|
614
|
-
| 测试耗时 | 最近 `health.runs` 次**全量**运行的墙钟、提交、层、是否全过;各层的墙钟不可比,一层一条走向线 | `<主检出>/tmp/test-ledger/*/*/ledger.json`(`OMNE_TEST_LEDGER_HOME` 可改根);全量运行是 `meta.base` 为 null 的那些(`run --all`,或计划判为全量的 `pnpm run check` 测试一步),可以只跑一层(`pnpm run check` 的测试一步快、慢两层各记一份),层取 `meta.tier
|
|
656
|
+
| 测试耗时 | 最近 `health.runs` 次**全量**运行的墙钟、提交、层、是否全过;各层的墙钟不可比,一层一条走向线 | `<主检出>/tmp/test-ledger/*/*/ledger.json`(`OMNE_TEST_LEDGER_HOME` 可改根);全量运行是 `meta.base` 为 null 的那些(`run --all`,或计划判为全量的 `pnpm run check` 测试一步),可以只跑一层(`pnpm run check` 的测试一步快、慢两层各记一份),层取 `meta.tier`,没有这一栏的旧账本按两层;受影响范围的运行带基线,不计入;含缓存命中(`meta.cache.hits` 非空)的账本只列实际跑了的成员,墙钟不代表一次全量,也不计入 |
|
|
615
657
|
| 债的走向 | 每个指标一条小折线(虚线是提醒线与处置线,蓝点是最新值)、最新值与最新带位;当前或曾经处于处置的成员,各项预算的读数走向 | `trend.jsonl`;同一提交多条取最后一条,按提交时间排 |
|
|
616
658
|
| 对照表条数 | 五类各多少条、不合约定的行数、「现状」以「待建」开头的行数 | `docs/clean-loop.md`,与回路状态同一份解析 |
|
|
617
659
|
| 传感器最近一次有数据 | 每个指标最近一条带着它的值的快照是哪个提交、什么时候;从没有过数据的标出 | `trend.jsonl` |
|
|
@@ -639,7 +681,7 @@ pnpm run loop:health # --out 可改产物目录
|
|
|
639
681
|
|
|
640
682
|
## 契约 API 快照
|
|
641
683
|
|
|
642
|
-
契约成员是[
|
|
684
|
+
契约成员是[契约成员表](../../docs/engineering/delivery-lines.json)各组 `contracts` 列出的成员。卡对它们缺省只做可加改动,规则见[可加改动](../../docs/engineering/delivery.md#可加改动)。本命令给每个契约成员一份入库的 API 快照,并把两份快照之间的差异粗分为三类:`none` 表示没有变化;`additive` 表示改动对已有的读方与写方都不破坏;`review` 表示其余一切改动,需要人判断。它只报告,不拦截。行为契约(输入、快照内容、确定性、分类规则、已知限制、退出码与配置校验)见 [SPEC](src/declarations/SPEC.md)。
|
|
643
685
|
|
|
644
686
|
```sh
|
|
645
687
|
omne-contract-api --write # 从 dist 重写快照(先构建)
|
|
@@ -653,7 +695,7 @@ omne-contract-api --baseline <区块文件> # 逐成员从登记的提交比
|
|
|
653
695
|
|
|
654
696
|
配置在 `repo-toolchain.config.json` 的 `contractApi` 一节,有两个键:
|
|
655
697
|
|
|
656
|
-
- `members
|
|
698
|
+
- `members`:契约成员表的路径。
|
|
657
699
|
- `snapshot`:快照路径模板,以 `.md` 结尾,至少含 `{member}`(成员目录)或 `{package}`(不带 scope 的包名)之一。
|
|
658
700
|
|
|
659
701
|
这一节有别的键、缺键或值不合条件时,命令报错退出。两个成员算出同一个快照路径时,命令也报错退出。
|
|
@@ -670,12 +712,12 @@ omne-contract-api --baseline <区块文件> # 逐成员从登记的提交比
|
|
|
670
712
|
|
|
671
713
|
- 改了契约成员公开面的卡,在同一个 PR 里构建并运行 `--write`,把快照的变化一起提交。`--check` 报不一致时,先判断改动是否有意。
|
|
672
714
|
- 本工具改了快照格式(格式版本变了)时,全部快照要重新生成。
|
|
673
|
-
- 谁写首份快照、格式变化时谁重新生成,规则见[里程碑内的规则](../../docs/engineering/
|
|
715
|
+
- 谁写首份快照、格式变化时谁重新生成,规则见[里程碑内的规则](../../docs/engineering/delivery.md#破坏性契约改动)。
|
|
674
716
|
|
|
675
717
|
`--diff` 的前提:
|
|
676
718
|
|
|
677
719
|
- 它只比快照文件,不读 dist。先用 `--check` 确认工作树的快照与 dist 一致,或先运行 `--write`。
|
|
678
|
-
-
|
|
720
|
+
- 成员取基线与当前两份契约成员表的并集,每侧的快照路径按那一侧的包名算。基线上没有快照的成员整份算 `additive`。
|
|
679
721
|
- 判断改动是否可加时,传里程碑登记的基线提交。
|
|
680
722
|
|
|
681
723
|
快照摘要是快照文件字节的 SHA-256。`--check --json` 对每个有快照文件的成员给出 `sha256`。
|
|
@@ -53,6 +53,14 @@ export interface CommitTouch {
|
|
|
53
53
|
}
|
|
54
54
|
/** 纯函数:给碰过验收文件的提交与未提交的改动,判断这把锁有没有被破。 */
|
|
55
55
|
export declare function judge(touches: readonly CommitTouch[], uncommitted: readonly string[], config: AcceptanceLockConfig): Pick<LockReport, 'commits' | 'violations'>;
|
|
56
|
+
/**
|
|
57
|
+
* 范围里每个提交改到的路径,一次 `git log` 读完(逐个提交调 `diff-tree` 在 Windows 上一个提交要二三十毫秒)。
|
|
58
|
+
* 与逐个调 `git diff-tree --name-only --no-renames -r <-m|--cc> <提交>` 列出的路径相同:
|
|
59
|
+
* `-m` 让合并提交相对每个父提交各列一次(`log.diffMerges=separate` 钉住 `-m` 的含义,免得用户配置把它改成只比第一父),
|
|
60
|
+
* 同一提交的几段在这里合并;`--cc` 只列与每个父提交都不同的路径。`log.showRoot=false` 让根提交像 `diff-tree`
|
|
61
|
+
* 不加 `--root` 时那样不列路径;`--no-show-signature` 不让签名校验的输出混进来。
|
|
62
|
+
*/
|
|
63
|
+
export declare function namesByCommit(root: string, range: string, integration: boolean): Map<string, Set<string>>;
|
|
56
64
|
/** 读 Git:基线到当前工作树之间,验收文件发生了什么、谁改的。 */
|
|
57
65
|
export declare function inspect(root: string, base: string, config: AcceptanceLockConfig, head?: string, integration?: boolean): LockReport;
|
|
58
66
|
export declare function render(report: LockReport, config: AcceptanceLockConfig): string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/acceptance/lock.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAIxE,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AAI9D,MAAM,WAAW,oBAAoB;IACnC,iCAAiC;IACjC,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC,kCAAkC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,kEAAkE;IAClE,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;CACvC;AAYD,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,OAAO,GAAG,oBAAoB,CAU5E;AAED,wBAAgB,wBAAwB,CACtC,IAAI,GAAE,MAA8B,GACnC,oBAAoB,CAEtB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAOpF;AAED,kEAAkE;AAClE,eAAO,MAAM,kBAAkB,uCAAuC,CAAA;
|
|
1
|
+
{"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/acceptance/lock.ts"],"names":[],"mappings":"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"}
|