@descryy/core 0.4.0 → 0.5.1
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/dist/budget/reply.d.ts +11 -46
- package/dist/budget/reply.d.ts.map +1 -1
- package/dist/budget/reply.js +10 -39
- package/dist/budget/reply.js.map +1 -1
- package/dist/budget/size.d.ts +2 -21
- package/dist/budget/size.d.ts.map +1 -1
- package/dist/budget/size.js +3 -24
- package/dist/budget/size.js.map +1 -1
- package/dist/capabilities/preconditions.d.ts +7 -68
- package/dist/capabilities/preconditions.d.ts.map +1 -1
- package/dist/capabilities/preconditions.js +6 -57
- package/dist/capabilities/preconditions.js.map +1 -1
- package/dist/contracts/engine.d.ts +23 -11
- package/dist/contracts/engine.d.ts.map +1 -1
- package/dist/contracts/engine.js +23 -11
- package/dist/contracts/engine.js.map +1 -1
- package/dist/contracts/orphans.d.ts +18 -122
- package/dist/contracts/orphans.d.ts.map +1 -1
- package/dist/contracts/orphans.js +36 -134
- package/dist/contracts/orphans.js.map +1 -1
- package/dist/contracts/paths.d.ts +4 -114
- package/dist/contracts/paths.d.ts.map +1 -1
- package/dist/contracts/paths.js +7 -140
- package/dist/contracts/paths.js.map +1 -1
- package/dist/contracts/shapes.d.ts +13 -66
- package/dist/contracts/shapes.d.ts.map +1 -1
- package/dist/contracts/shapes.js +20 -91
- package/dist/contracts/shapes.js.map +1 -1
- package/dist/governance/budget.d.ts +12 -48
- package/dist/governance/budget.d.ts.map +1 -1
- package/dist/governance/budget.js +12 -48
- package/dist/governance/budget.js.map +1 -1
- package/dist/governance/candidate-boundary.d.ts +4 -32
- package/dist/governance/candidate-boundary.d.ts.map +1 -1
- package/dist/governance/candidate-boundary.js +4 -32
- package/dist/governance/candidate-boundary.js.map +1 -1
- package/dist/governance/escalation.d.ts +7 -45
- package/dist/governance/escalation.d.ts.map +1 -1
- package/dist/governance/escalation.js +7 -45
- package/dist/governance/escalation.js.map +1 -1
- package/dist/governance/fact-boundary.d.ts +7 -49
- package/dist/governance/fact-boundary.d.ts.map +1 -1
- package/dist/governance/fact-boundary.js +5 -43
- package/dist/governance/fact-boundary.js.map +1 -1
- package/dist/governance/finding-funnel.d.ts +11 -72
- package/dist/governance/finding-funnel.d.ts.map +1 -1
- package/dist/governance/finding-funnel.js +9 -68
- package/dist/governance/finding-funnel.js.map +1 -1
- package/dist/graph/build.d.ts +9 -90
- package/dist/graph/build.d.ts.map +1 -1
- package/dist/graph/build.js +15 -62
- package/dist/graph/build.js.map +1 -1
- package/dist/graph/cross-language.d.ts +4 -43
- package/dist/graph/cross-language.d.ts.map +1 -1
- package/dist/graph/cross-language.js +9 -77
- package/dist/graph/cross-language.js.map +1 -1
- package/dist/graph/merge.d.ts +8 -88
- package/dist/graph/merge.d.ts.map +1 -1
- package/dist/graph/merge.js +9 -93
- package/dist/graph/merge.js.map +1 -1
- package/dist/graph/observed-tests.d.ts +7 -68
- package/dist/graph/observed-tests.d.ts.map +1 -1
- package/dist/graph/observed-tests.js +5 -60
- package/dist/graph/observed-tests.js.map +1 -1
- package/dist/graph/persist.d.ts +2 -25
- package/dist/graph/persist.d.ts.map +1 -1
- package/dist/graph/persist.js +2 -25
- package/dist/graph/persist.js.map +1 -1
- package/dist/graph/runtime-confirmation.d.ts +14 -91
- package/dist/graph/runtime-confirmation.d.ts.map +1 -1
- package/dist/graph/runtime-confirmation.js +19 -103
- package/dist/graph/runtime-confirmation.js.map +1 -1
- package/dist/ledger/mint.d.ts +9 -43
- package/dist/ledger/mint.d.ts.map +1 -1
- package/dist/ledger/mint.js +15 -65
- package/dist/ledger/mint.js.map +1 -1
- package/dist/ledger/resolve.d.ts +13 -81
- package/dist/ledger/resolve.d.ts.map +1 -1
- package/dist/ledger/resolve.js +13 -76
- package/dist/ledger/resolve.js.map +1 -1
- package/dist/multipr/fingerprint.d.ts +5 -46
- package/dist/multipr/fingerprint.d.ts.map +1 -1
- package/dist/multipr/fingerprint.js +22 -74
- package/dist/multipr/fingerprint.js.map +1 -1
- package/dist/multipr/hidden-dependency.d.ts +13 -73
- package/dist/multipr/hidden-dependency.d.ts.map +1 -1
- package/dist/multipr/hidden-dependency.js +12 -63
- package/dist/multipr/hidden-dependency.js.map +1 -1
- package/dist/multipr/mechanical.d.ts +25 -160
- package/dist/multipr/mechanical.d.ts.map +1 -1
- package/dist/multipr/mechanical.js +21 -137
- package/dist/multipr/mechanical.js.map +1 -1
- package/dist/multipr/migration-heads.d.ts +18 -105
- package/dist/multipr/migration-heads.d.ts.map +1 -1
- package/dist/multipr/migration-heads.js +15 -84
- package/dist/multipr/migration-heads.js.map +1 -1
- package/dist/multipr/overlap.d.ts +16 -94
- package/dist/multipr/overlap.d.ts.map +1 -1
- package/dist/multipr/overlap.js +25 -105
- package/dist/multipr/overlap.js.map +1 -1
- package/dist/multipr/scope-store.d.ts +15 -80
- package/dist/multipr/scope-store.d.ts.map +1 -1
- package/dist/multipr/scope-store.js +17 -87
- package/dist/multipr/scope-store.js.map +1 -1
- package/dist/multipr/superseded.d.ts +10 -95
- package/dist/multipr/superseded.d.ts.map +1 -1
- package/dist/multipr/superseded.js +7 -60
- package/dist/multipr/superseded.js.map +1 -1
- package/dist/query/confirmed-facts.d.ts +12 -58
- package/dist/query/confirmed-facts.d.ts.map +1 -1
- package/dist/query/confirmed-facts.js +8 -47
- package/dist/query/confirmed-facts.js.map +1 -1
- package/dist/query/declared-value-closure.d.ts +13 -104
- package/dist/query/declared-value-closure.d.ts.map +1 -1
- package/dist/query/declared-value-closure.js +15 -104
- package/dist/query/declared-value-closure.js.map +1 -1
- package/dist/query/memory.d.ts +4 -16
- package/dist/query/memory.d.ts.map +1 -1
- package/dist/query/memory.js +9 -22
- package/dist/query/memory.js.map +1 -1
- package/dist/query/prominence.d.ts +6 -55
- package/dist/query/prominence.d.ts.map +1 -1
- package/dist/query/prominence.js +6 -55
- package/dist/query/prominence.js.map +1 -1
- package/dist/query/provider.d.ts +27 -93
- package/dist/query/provider.d.ts.map +1 -1
- package/dist/query/provider.js +8 -29
- package/dist/query/provider.js.map +1 -1
- package/dist/query/queries.d.ts +15 -65
- package/dist/query/queries.d.ts.map +1 -1
- package/dist/query/queries.js +30 -104
- package/dist/query/queries.js.map +1 -1
- package/dist/query/refusal-fetch.d.ts +8 -85
- package/dist/query/refusal-fetch.d.ts.map +1 -1
- package/dist/query/refusal-fetch.js +11 -93
- package/dist/query/refusal-fetch.js.map +1 -1
- package/dist/query/refusal-questions.d.ts +17 -92
- package/dist/query/refusal-questions.d.ts.map +1 -1
- package/dist/query/refusal-questions.js +14 -78
- package/dist/query/refusal-questions.js.map +1 -1
- package/dist/query/resolution-floor.d.ts +3 -23
- package/dist/query/resolution-floor.d.ts.map +1 -1
- package/dist/query/resolution-floor.js +3 -23
- package/dist/query/resolution-floor.js.map +1 -1
- package/dist/query/root-cause-score.d.ts +11 -161
- package/dist/query/root-cause-score.d.ts.map +1 -1
- package/dist/query/root-cause-score.js +6 -137
- package/dist/query/root-cause-score.js.map +1 -1
- package/dist/query/row-closure-picture.d.ts +5 -67
- package/dist/query/row-closure-picture.d.ts.map +1 -1
- package/dist/query/row-closure-picture.js +6 -67
- package/dist/query/row-closure-picture.js.map +1 -1
- package/dist/query/similar-incidents.d.ts +6 -41
- package/dist/query/similar-incidents.d.ts.map +1 -1
- package/dist/query/similar-incidents.js +15 -69
- package/dist/query/similar-incidents.js.map +1 -1
- package/dist/query/sqlite.d.ts +3 -7
- package/dist/query/sqlite.d.ts.map +1 -1
- package/dist/query/sqlite.js +9 -19
- package/dist/query/sqlite.js.map +1 -1
- package/dist/query/test-coverage.d.ts +5 -45
- package/dist/query/test-coverage.d.ts.map +1 -1
- package/dist/query/test-coverage.js +10 -53
- package/dist/query/test-coverage.js.map +1 -1
- package/dist/query/traverse.d.ts +22 -126
- package/dist/query/traverse.d.ts.map +1 -1
- package/dist/query/traverse.js +25 -126
- package/dist/query/traverse.js.map +1 -1
- package/dist/query/unresolved.d.ts +19 -164
- package/dist/query/unresolved.d.ts.map +1 -1
- package/dist/query/unresolved.js +11 -138
- package/dist/query/unresolved.js.map +1 -1
- package/dist/query/verification-status.d.ts +12 -109
- package/dist/query/verification-status.d.ts.map +1 -1
- package/dist/query/verification-status.js +9 -99
- package/dist/query/verification-status.js.map +1 -1
- package/dist/recording/migrate.d.ts +4 -10
- package/dist/recording/migrate.d.ts.map +1 -1
- package/dist/recording/migrate.js +4 -10
- package/dist/recording/migrate.js.map +1 -1
- package/dist/recording/reader.d.ts +2 -7
- package/dist/recording/reader.d.ts.map +1 -1
- package/dist/recording/reader.js +2 -7
- package/dist/recording/reader.js.map +1 -1
- package/dist/recording/redact.d.ts +6 -57
- package/dist/recording/redact.d.ts.map +1 -1
- package/dist/recording/redact.js +8 -64
- package/dist/recording/redact.js.map +1 -1
- package/dist/recording/schema.d.ts +3 -38
- package/dist/recording/schema.d.ts.map +1 -1
- package/dist/recording/schema.js +3 -38
- package/dist/recording/schema.js.map +1 -1
- package/dist/recording/writer.d.ts +11 -74
- package/dist/recording/writer.d.ts.map +1 -1
- package/dist/recording/writer.js +3 -43
- package/dist/recording/writer.js.map +1 -1
- package/dist/scoping/fanout.d.ts +6 -68
- package/dist/scoping/fanout.d.ts.map +1 -1
- package/dist/scoping/fanout.js +6 -68
- package/dist/scoping/fanout.js.map +1 -1
- package/dist/scoping/score.d.ts +20 -70
- package/dist/scoping/score.d.ts.map +1 -1
- package/dist/scoping/score.js +20 -70
- package/dist/scoping/score.js.map +1 -1
- package/dist/scoping/tiers.d.ts +4 -16
- package/dist/scoping/tiers.d.ts.map +1 -1
- package/dist/scoping/tiers.js +4 -16
- package/dist/scoping/tiers.js.map +1 -1
- package/dist/scoping/traverse.d.ts +3 -25
- package/dist/scoping/traverse.d.ts.map +1 -1
- package/dist/scoping/traverse.js +14 -49
- package/dist/scoping/traverse.js.map +1 -1
- package/dist/scoping/weights.d.ts +10 -74
- package/dist/scoping/weights.d.ts.map +1 -1
- package/dist/scoping/weights.js +14 -86
- package/dist/scoping/weights.js.map +1 -1
- package/dist/sources/confirmed/incidents.d.ts +5 -35
- package/dist/sources/confirmed/incidents.d.ts.map +1 -1
- package/dist/sources/confirmed/incidents.js +14 -48
- package/dist/sources/confirmed/incidents.js.map +1 -1
- package/dist/sources/git/diff.d.ts +93 -63
- package/dist/sources/git/diff.d.ts.map +1 -1
- package/dist/sources/git/diff.js +200 -81
- package/dist/sources/git/diff.js.map +1 -1
- package/dist/sources/git/env.d.ts +7 -0
- package/dist/sources/git/env.d.ts.map +1 -1
- package/dist/sources/git/env.js +10 -11
- package/dist/sources/git/env.js.map +1 -1
- package/dist/sources/git/history.d.ts +64 -84
- package/dist/sources/git/history.d.ts.map +1 -1
- package/dist/sources/git/history.js +141 -112
- package/dist/sources/git/history.js.map +1 -1
- package/dist/sources/git/incidents.d.ts +13 -75
- package/dist/sources/git/incidents.d.ts.map +1 -1
- package/dist/sources/git/incidents.js +21 -91
- package/dist/sources/git/incidents.js.map +1 -1
- package/dist/sources/git/index.d.ts +5 -3
- package/dist/sources/git/index.d.ts.map +1 -1
- package/dist/sources/git/index.js +3 -2
- package/dist/sources/git/index.js.map +1 -1
- package/dist/sources/git/source.d.ts +9 -79
- package/dist/sources/git/source.d.ts.map +1 -1
- package/dist/sources/git/source.js +33 -133
- package/dist/sources/git/source.js.map +1 -1
- package/dist/sources/migrations/across-change.d.ts +94 -0
- package/dist/sources/migrations/across-change.d.ts.map +1 -0
- package/dist/sources/migrations/across-change.js +278 -0
- package/dist/sources/migrations/across-change.js.map +1 -0
- package/dist/sources/migrations/dialects.d.ts +20 -36
- package/dist/sources/migrations/dialects.d.ts.map +1 -1
- package/dist/sources/migrations/dialects.js +11 -36
- package/dist/sources/migrations/dialects.js.map +1 -1
- package/dist/sources/migrations/index.d.ts +3 -1
- package/dist/sources/migrations/index.d.ts.map +1 -1
- package/dist/sources/migrations/index.js +2 -1
- package/dist/sources/migrations/index.js.map +1 -1
- package/dist/sources/migrations/read.d.ts +14 -79
- package/dist/sources/migrations/read.d.ts.map +1 -1
- package/dist/sources/migrations/read.js +14 -89
- package/dist/sources/migrations/read.js.map +1 -1
- package/dist/sources/workspace/workspace.d.ts +6 -42
- package/dist/sources/workspace/workspace.d.ts.map +1 -1
- package/dist/sources/workspace/workspace.js +10 -53
- package/dist/sources/workspace/workspace.js.map +1 -1
- package/dist/store/driver/driver.d.ts +9 -38
- package/dist/store/driver/driver.d.ts.map +1 -1
- package/dist/store/driver/driver.js +4 -22
- package/dist/store/driver/driver.js.map +1 -1
- package/dist/store/driver/node-sqlite.d.ts +3 -12
- package/dist/store/driver/node-sqlite.d.ts.map +1 -1
- package/dist/store/driver/node-sqlite.js +4 -18
- package/dist/store/driver/node-sqlite.js.map +1 -1
- package/dist/store/index.d.ts +2 -7
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +4 -10
- package/dist/store/index.js.map +1 -1
- package/dist/store/migrate.d.ts +14 -50
- package/dist/store/migrate.d.ts.map +1 -1
- package/dist/store/migrate.js +15 -52
- package/dist/store/migrate.js.map +1 -1
- package/dist/store/reader.d.ts +19 -84
- package/dist/store/reader.d.ts.map +1 -1
- package/dist/store/reader.js +25 -92
- package/dist/store/reader.js.map +1 -1
- package/dist/store/schema.d.ts +14 -76
- package/dist/store/schema.d.ts.map +1 -1
- package/dist/store/schema.js +14 -76
- package/dist/store/schema.js.map +1 -1
- package/dist/store/writer.d.ts +14 -88
- package/dist/store/writer.d.ts.map +1 -1
- package/dist/store/writer.js +29 -123
- package/dist/store/writer.js.map +1 -1
- package/dist/tiers/certify.d.ts +46 -281
- package/dist/tiers/certify.d.ts.map +1 -1
- package/dist/tiers/certify.js +46 -226
- package/dist/tiers/certify.js.map +1 -1
- package/dist/tiers/ladder.d.ts +7 -51
- package/dist/tiers/ladder.d.ts.map +1 -1
- package/dist/tiers/ladder.js +13 -89
- package/dist/tiers/ladder.js.map +1 -1
- package/dist/validation/attributes.d.ts +6 -55
- package/dist/validation/attributes.d.ts.map +1 -1
- package/dist/validation/attributes.js +6 -55
- package/dist/validation/attributes.js.map +1 -1
- package/dist/validation/config-graph.d.ts +7 -56
- package/dist/validation/config-graph.d.ts.map +1 -1
- package/dist/validation/config-graph.js +15 -61
- package/dist/validation/config-graph.js.map +1 -1
- package/dist/validation/env.d.ts +47 -8
- package/dist/validation/env.d.ts.map +1 -1
- package/dist/validation/env.js +119 -31
- package/dist/validation/env.js.map +1 -1
- package/dist/validation/index.d.ts +2 -0
- package/dist/validation/index.d.ts.map +1 -1
- package/dist/validation/index.js +1 -0
- package/dist/validation/index.js.map +1 -1
- package/dist/validation/join-substitution.d.ts +22 -120
- package/dist/validation/join-substitution.d.ts.map +1 -1
- package/dist/validation/join-substitution.js +13 -90
- package/dist/validation/join-substitution.js.map +1 -1
- package/dist/validation/migration-integrity.d.ts +11 -72
- package/dist/validation/migration-integrity.d.ts.map +1 -1
- package/dist/validation/migration-integrity.js +16 -79
- package/dist/validation/migration-integrity.js.map +1 -1
- package/dist/validation/migrations.d.ts +22 -101
- package/dist/validation/migrations.d.ts.map +1 -1
- package/dist/validation/migrations.js +19 -83
- package/dist/validation/migrations.js.map +1 -1
- package/dist/validation/nodes.d.ts +3 -1
- package/dist/validation/nodes.d.ts.map +1 -1
- package/dist/validation/nodes.js +3 -1
- package/dist/validation/nodes.js.map +1 -1
- package/dist/validation/orm-registration.d.ts +106 -0
- package/dist/validation/orm-registration.d.ts.map +1 -0
- package/dist/validation/orm-registration.js +191 -0
- package/dist/validation/orm-registration.js.map +1 -0
- package/dist/validation/rollback.d.ts +10 -73
- package/dist/validation/rollback.d.ts.map +1 -1
- package/dist/validation/rollback.js +15 -82
- package/dist/validation/rollback.js.map +1 -1
- package/dist/validation/route-drift.d.ts +9 -62
- package/dist/validation/route-drift.d.ts.map +1 -1
- package/dist/validation/route-drift.js +7 -52
- package/dist/validation/route-drift.js.map +1 -1
- package/dist/validation/sources.d.ts +16 -94
- package/dist/validation/sources.d.ts.map +1 -1
- package/dist/validation/sources.js +51 -147
- package/dist/validation/sources.js.map +1 -1
- package/dist/worker/pool.d.ts +6 -45
- package/dist/worker/pool.d.ts.map +1 -1
- package/dist/worker/pool.js +5 -42
- package/dist/worker/pool.js.map +1 -1
- package/dist/worker/protocol.d.ts +7 -20
- package/dist/worker/protocol.d.ts.map +1 -1
- package/dist/worker/protocol.js +3 -10
- package/dist/worker/protocol.js.map +1 -1
- package/dist/worker/traversal.worker.d.ts +2 -21
- package/dist/worker/traversal.worker.d.ts.map +1 -1
- package/dist/worker/traversal.worker.js +4 -23
- package/dist/worker/traversal.worker.js.map +1 -1
- package/package.json +11 -2
|
@@ -1,95 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Which commits
|
|
3
|
-
*
|
|
4
|
-
* Split out of `source.ts` when the answer stopped being one regex. The git
|
|
5
|
-
* source minted an `INCIDENT` for exactly one thing — a commit body carrying
|
|
6
|
-
* `This reverts commit <40 hex>` — and that produced **zero** incidents across
|
|
7
|
-
* three measured repositories (734/459/203 commits) and two in a real product
|
|
8
|
-
* repository. `similarIncidents` was therefore built, tested, correct and
|
|
9
|
-
* starved: its recall is not 0%, it is not computable, because it has never
|
|
10
|
-
* been given a real incident to find.
|
|
11
|
-
*
|
|
12
|
-
* ## The rule every mechanism here answers to
|
|
13
|
-
*
|
|
14
|
-
* `INCIDENT` is an EARNED node (DEC-017). It is never dropped, it survives
|
|
15
|
-
* every rebuild, and `INCIDENT_CORRELATED` biases diff-scoping traversal toward
|
|
16
|
-
* the files it names for as long as the store exists. A wrong incident is not a
|
|
17
|
-
* bad answer that a later run corrects — it is unrecoverable pollution in the
|
|
18
|
-
* one table that cannot be recomputed away. So:
|
|
19
|
-
*
|
|
20
|
-
* **Every mechanism rests on something a person declared. None rests on
|
|
21
|
-
* something Descry inferred.**
|
|
22
|
-
*
|
|
23
|
-
* A revert trailer is written by `git revert`. A `Revert "…"` subject is typed
|
|
24
|
-
* by a person or by GitHub's own button on their behalf. `Fixes #123` is a
|
|
25
|
-
* developer stating that something was broken and this commit fixed it. What is
|
|
26
|
-
* deliberately *not* here is any reading of "fix", "hotfix" or "bug" in prose —
|
|
27
|
-
* the original mechanism's own comment says why, and it applies unchanged to
|
|
28
|
-
* every mechanism added since: matching on the word "fix" would classify
|
|
29
|
-
* ordinary work as an incident.
|
|
30
|
-
*
|
|
31
|
-
* ## Refusals, not guesses
|
|
32
|
-
*
|
|
33
|
-
* A `Revert "X"` naming a subject this history does not contain, or containing
|
|
34
|
-
* twice, produces a `DetectedRefusal` rather than a ranked guess. Two candidates
|
|
35
|
-
* is a genuine ambiguity and picking the nearer one would be recency standing in
|
|
36
|
-
* for evidence — the same discipline every resolver in this project follows.
|
|
37
|
-
*
|
|
38
|
-
* See `DEC-NEXT-incident-minting-beyond-explicit-reverts`.
|
|
2
|
+
* Which commits describe a failure. `INCIDENT` is EARNED (DEC-017, never dropped, biases traversal permanently), so every mechanism rests on something a person declared — never Descry inferring "fix"/"bug" from prose.
|
|
3
|
+
* An ambiguous Revert is a DetectedRefusal, not a ranked guess. See DEC-NEXT-incident-minting-beyond-explicit-reverts.
|
|
39
4
|
*/
|
|
40
5
|
/** `git revert` writes this. Machine-generated, and the strongest signal available. */
|
|
41
6
|
const REVERT_TRAILER = /This reverts commit ([0-9a-f]{40})/;
|
|
42
|
-
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* Anchored at the start and requiring the quotes: `Revert the auth change` is
|
|
47
|
-
* prose about what the commit does, not a reference to a specific commit, and
|
|
48
|
-
* reading it as one would be exactly the inference this module refuses to make.
|
|
49
|
-
*/
|
|
7
|
+
/** `Revert "the original subject"` form, written by a person or GitHub's
|
|
8
|
+
* button. Anchored + requires quotes: unquoted `Revert the auth change` is
|
|
9
|
+
* prose, not a commit reference, and reading it as one is the inference refused here. */
|
|
50
10
|
const REVERT_SUBJECT = /^Revert\s+"(.+)"\s*$/;
|
|
51
|
-
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* `Fixes #123` is a developer stating that something was broken. `See #123` and
|
|
55
|
-
* `Part of #124` are not — they relate a commit to an issue and say nothing
|
|
56
|
-
* about a defect. The verb is what carries the claim, so the verb is what is
|
|
57
|
-
* matched; a bare `#123` mints nothing.
|
|
58
|
-
*
|
|
59
|
-
* `GH-123` is GitHub's own cross-reference form and means the same thing.
|
|
60
|
-
*/
|
|
11
|
+
/** Closed list of fix-shaped verbs, immediately before the reference. `Fixes
|
|
12
|
+
* #123` claims a defect; `See #123` doesn't — a bare `#123` mints nothing.
|
|
13
|
+
* `GH-123` is GitHub's equivalent cross-reference form. */
|
|
61
14
|
const ISSUE_VERBS = "fix|fixes|fixed|close|closes|closed|resolve|resolves|resolved";
|
|
62
15
|
/** In the subject, anywhere: a subject is a claim about the commit itself. */
|
|
63
16
|
const SUBJECT_ISSUE = new RegExp(`\\b(?:${ISSUE_VERBS})\\s+(?:#|GH-)(\\d+)\\b`, "gi");
|
|
64
|
-
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* Measured, not supposed. Run over this repository's own history, the
|
|
69
|
-
* anywhere-in-the-body form matched three commits, and all three were prose
|
|
70
|
-
* *about* the convention rather than uses of it: a sentence quoting
|
|
71
|
-
* `"Fixes #123"` as an example, and a bullet reading
|
|
72
|
-
* `- issue-reference: \`Fixes #123\` and its closed list…`. A commit message
|
|
73
|
-
* discussing the convention is not a commit message using it, and an EARNED
|
|
74
|
-
* node minted from one is permanent.
|
|
75
|
-
*
|
|
76
|
-
* The trailer position is where the convention actually lives — it is what
|
|
77
|
-
* GitHub's own tooling emits and what a template puts there — so this costs
|
|
78
|
-
* almost no real recall and removes a whole class of false positive. Rule 2:
|
|
79
|
-
* when in doubt, omit.
|
|
17
|
+
/** In the body, only in trailer position (line start). Measured: the
|
|
18
|
+
* anywhere-in-body form matched 3 commits here, all prose *about* the
|
|
19
|
+
* convention, not uses of it — and an EARNED node minted from one is permanent. Trailer position is where the convention actually lives. Rule 2.
|
|
80
20
|
*/
|
|
81
21
|
const BODY_ISSUE = new RegExp(`^[ \\t]*(?:${ISSUE_VERBS})\\s+(?:#|GH-)(\\d+)\\b`, "gim");
|
|
82
22
|
function pathsOf(commit) {
|
|
83
23
|
return [...new Set(commit.changes.map((c) => c.path))].sort();
|
|
84
24
|
}
|
|
85
|
-
/**
|
|
86
|
-
*
|
|
87
|
-
* not contain.
|
|
88
|
-
*
|
|
89
|
-
* `commits` is the history as `readHistory` returns it — newest first. Order is
|
|
90
|
-
* not relied on for correctness: a revert's target is found by timestamp, so
|
|
91
|
-
* the result is identical for any permutation of the same commits.
|
|
92
|
-
*/
|
|
25
|
+
/** Every incident this history declares, plus every revert whose target it
|
|
26
|
+
* lacks. Order-independent: a revert's target is found by timestamp. */
|
|
93
27
|
export function detectIncidents(commits) {
|
|
94
28
|
const incidents = [];
|
|
95
29
|
const refusals = [];
|
|
@@ -104,9 +38,8 @@ export function detectIncidents(commits) {
|
|
|
104
38
|
existing.push(commit);
|
|
105
39
|
}
|
|
106
40
|
for (const commit of commits) {
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
// mechanism would mint one incident twice under two different names.
|
|
41
|
+
// Trailer first, exclusively: git revert writes both trailer and subject,
|
|
42
|
+
// so reading the subject too would mint one incident under two names.
|
|
110
43
|
const revertedSha = REVERT_TRAILER.exec(commit.body)?.[1];
|
|
111
44
|
if (revertedSha !== undefined) {
|
|
112
45
|
const target = bySha.get(revertedSha);
|
|
@@ -125,9 +58,8 @@ export function detectIncidents(commits) {
|
|
|
125
58
|
}
|
|
126
59
|
const quoted = REVERT_SUBJECT.exec(commit.subject)?.[1];
|
|
127
60
|
if (quoted !== undefined) {
|
|
128
|
-
// Backwards only
|
|
129
|
-
//
|
|
130
|
-
// different commit that happens to share a name.
|
|
61
|
+
// Backwards only: a commit can't revert something written after it, and
|
|
62
|
+
// a same-subject commit landing later just happens to share a name.
|
|
131
63
|
const candidates = (bySubject.get(quoted) ?? []).filter((c) => c.timestamp < commit.timestamp);
|
|
132
64
|
if (candidates.length === 1) {
|
|
133
65
|
const target = candidates[0];
|
|
@@ -157,10 +89,8 @@ export function detectIncidents(commits) {
|
|
|
157
89
|
}
|
|
158
90
|
continue;
|
|
159
91
|
}
|
|
160
|
-
// An issue reference
|
|
161
|
-
//
|
|
162
|
-
// trailer position — see `BODY_ISSUE` for the three false positives that
|
|
163
|
-
// distinction was measured against.
|
|
92
|
+
// An issue reference claims a defect. Read from the subject anywhere,
|
|
93
|
+
// from the body only in trailer position — see BODY_ISSUE's measurement.
|
|
164
94
|
const refs = new Set();
|
|
165
95
|
for (const match of commit.subject.matchAll(SUBJECT_ISSUE))
|
|
166
96
|
refs.add(`#${match[1]}`);
|
|
@@ -176,8 +106,8 @@ export function detectIncidents(commits) {
|
|
|
176
106
|
});
|
|
177
107
|
}
|
|
178
108
|
}
|
|
179
|
-
// Deterministic: two runs
|
|
180
|
-
//
|
|
109
|
+
// Deterministic: two runs must produce a byte-identical batch, or the
|
|
110
|
+
// store's content hash moves for no reason.
|
|
181
111
|
incidents.sort((a, b) => a.fix.sha.localeCompare(b.fix.sha) || (a.issueRef ?? "").localeCompare(b.issueRef ?? ""));
|
|
182
112
|
refusals.sort((a, b) => a.fixSha.localeCompare(b.fixSha) || a.rawTarget.localeCompare(b.rawTarget));
|
|
183
113
|
unresolvedTrailers.sort((a, b) => a.fix.sha.localeCompare(b.fix.sha));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"incidents.js","sourceRoot":"","sources":["../../../src/sources/git/incidents.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"incidents.js","sourceRoot":"","sources":["../../../src/sources/git/incidents.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export { createGitSource, revertedShaOf, GIT_SOURCE_ID, GIT_SOURCE_VERSION, UNDIRECTED_EDGE_TYPES, } from "./source.ts";
|
|
2
2
|
export type { GitSourceOptions } from "./source.ts";
|
|
3
|
-
export { readHistory, gitHead, isGitRepository, filesInCommit, changedFiles, resolveCommitBySha, logForPath, } from "./history.ts";
|
|
3
|
+
export { readHistory, gitHead, isGitRepository, GitUnavailableError, isPathTrackedByGit, filesInCommit, changedFiles, resolveCommitBySha, logForPath, } from "./history.ts";
|
|
4
4
|
export type { Commit, CommitChange, HistoryOptions, PathLogCommit, PathLogOptions, PathLogResult, } from "./history.ts";
|
|
5
|
-
export { gitDiff, gitWorkingTreeDiff, TOTAL_PATCH_BUDGET_REASON_PREFIX } from "./diff.ts";
|
|
6
|
-
export
|
|
5
|
+
export { addedLineRanges, gitDiff, gitWorkingTreeChange, gitWorkingTreeDiff, TOTAL_PATCH_BUDGET_REASON_PREFIX, } from "./diff.ts";
|
|
6
|
+
export { uncommittedAmong, workingTreeChangedFiles } from "./history.ts";
|
|
7
|
+
export type { WorkingTreeFilesOptions } from "./history.ts";
|
|
8
|
+
export type { GitDiffFile, GitDiffOptions, GitWorkingTreeChange, GitWorkingTreeChangeOptions, GitWorkingTreeDiffOptions, LineRange, } from "./diff.ts";
|
|
7
9
|
export { detectIncidents } from "./incidents.ts";
|
|
8
10
|
export type { DetectedIncident, DetectedRefusal, IncidentDetection, IncidentMechanism, UnresolvedTrailer, } from "./incidents.ts";
|
|
9
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/sources/git/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,EACL,WAAW,EACX,OAAO,EACP,eAAe,EACf,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,MAAM,EACN,YAAY,EACZ,cAAc,EACd,aAAa,EACb,cAAc,EACd,aAAa,GACd,MAAM,cAAc,CAAC;AAEtB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/sources/git/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,EACL,WAAW,EACX,OAAO,EACP,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,MAAM,EACN,YAAY,EACZ,cAAc,EACd,aAAa,EACb,cAAc,EACd,aAAa,GACd,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,eAAe,EACf,OAAO,EACP,oBAAoB,EACpB,kBAAkB,EAClB,gCAAgC,GACjC,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACzE,YAAY,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC5D,YAAY,EACV,WAAW,EACX,cAAc,EACd,oBAAoB,EACpB,2BAA2B,EAC3B,yBAAyB,EACzB,SAAS,GACV,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { createGitSource, revertedShaOf, GIT_SOURCE_ID, GIT_SOURCE_VERSION, UNDIRECTED_EDGE_TYPES, } from "./source.js";
|
|
2
|
-
export { readHistory, gitHead, isGitRepository, filesInCommit, changedFiles, resolveCommitBySha, logForPath, } from "./history.js";
|
|
3
|
-
export { gitDiff, gitWorkingTreeDiff, TOTAL_PATCH_BUDGET_REASON_PREFIX } from "./diff.js";
|
|
2
|
+
export { readHistory, gitHead, isGitRepository, GitUnavailableError, isPathTrackedByGit, filesInCommit, changedFiles, resolveCommitBySha, logForPath, } from "./history.js";
|
|
3
|
+
export { addedLineRanges, gitDiff, gitWorkingTreeChange, gitWorkingTreeDiff, TOTAL_PATCH_BUDGET_REASON_PREFIX, } from "./diff.js";
|
|
4
|
+
export { uncommittedAmong, workingTreeChangedFiles } from "./history.js";
|
|
4
5
|
export { detectIncidents } from "./incidents.js";
|
|
5
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sources/git/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,WAAW,EACX,OAAO,EACP,eAAe,EACf,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,UAAU,GACX,MAAM,cAAc,CAAC;AAUtB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sources/git/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,WAAW,EACX,OAAO,EACP,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,UAAU,GACX,MAAM,cAAc,CAAC;AAUtB,OAAO,EACL,eAAe,EACf,OAAO,EACP,oBAAoB,EACpB,kBAAkB,EAClB,gCAAgC,GACjC,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAWzE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -1,93 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* that split exists: history is a producer of IR with no parser, no language and
|
|
6
|
-
* no resolution beyond R0, and without the narrower interface it would need a
|
|
7
|
-
* second write path — and a second write path is how un-provenanced rows reach
|
|
8
|
-
* storage.
|
|
9
|
-
*
|
|
10
|
-
* ## Everything here is R0, and that is not a formality
|
|
11
|
-
*
|
|
12
|
-
* Co-change is not code analysis. It observes that two files were edited in the
|
|
13
|
-
* same commit, which is evidence about *people*, not about program structure.
|
|
14
|
-
* R0's confidence ceiling (DEC-019) therefore caps every edge this source emits
|
|
15
|
-
* at 0.5, and §11A.5's reliability cap makes any finding resting on one Class C
|
|
16
|
-
* — a behavioural prediction that must be live-confirmed or dropped. That is the
|
|
17
|
-
* correct treatment: "these two files usually change together" is a hint for a
|
|
18
|
-
* human, never a claim about what breaks.
|
|
19
|
-
*
|
|
20
|
-
* ## Precision over recall, applied three times
|
|
21
|
-
*
|
|
22
|
-
* 1. **Merge commits are excluded from co-change.** A merge's file list is the
|
|
23
|
-
* union of both branches, so counting it would report every file in a large
|
|
24
|
-
* merge as coupled to every other. This exclusion is scoped to co-change —
|
|
25
|
-
* it does **not** apply to resolving what a revert names (see below): a
|
|
26
|
-
* revert of "Merge pull request #N" is a real incident whose target
|
|
27
|
-
* happens to be a merge commit, and excluding it from co-change is not a
|
|
28
|
-
* reason to also make it unresolvable as an incident.
|
|
29
|
-
* 2. **Large commits are excluded.** A commit touching hundreds of files is a
|
|
30
|
-
* reformat or a dependency bump; including it adds O(n²) edges that mean
|
|
31
|
-
* nothing.
|
|
32
|
-
* 3. **Only explicit reverts become incidents.** A commit whose message merely
|
|
33
|
-
* contains "fix" is not evidence of an incident. `git revert` writes a
|
|
34
|
-
* machine-generated `This reverts commit <sha>.` line, and that is the only
|
|
35
|
-
* signal used.
|
|
36
|
-
*
|
|
37
|
-
* ## Resolving what a revert names
|
|
38
|
-
*
|
|
39
|
-
* `readHistory` indexes commits reachable from `HEAD`, minus merges. A revert
|
|
40
|
-
* commit's target sha can miss that index for two reasons that have nothing to
|
|
41
|
-
* do with whether the incident is real: the target is a merge commit (excluded
|
|
42
|
-
* above), or the target was never merged as itself — a squash/rebase-merge
|
|
43
|
-
* workflow (GitHub's default) discards the original commits and only the
|
|
44
|
-
* squashed commit survives on `HEAD`, so "Revert PR #N" names a sha that is
|
|
45
|
-
* either real-but-unreachable (still sitting on an abandoned branch) or
|
|
46
|
-
* genuinely gone (garbage-collected after the branch was deleted). Measured
|
|
47
|
-
* against 5 real repos, 6 of 9 real reverts fell into these two buckets and
|
|
48
|
-
* were silently dropped by a naive index lookup.
|
|
49
|
-
*
|
|
50
|
-
* `resolveCommitBySha` is the fallback: it goes straight to the object
|
|
51
|
-
* database (`git cat-file` / `git diff-tree`), which enforces neither
|
|
52
|
-
* constraint `readHistory` applies. It resolves the merge case and the
|
|
53
|
-
* unreachable-but-present case. Only the genuinely-gone case still fails, and
|
|
54
|
-
* that failure is disclosed via `unresolved` (below) rather than dropped with
|
|
55
|
-
* no trace — this is the fallback CLAUDE.md rule 7 requires labelling.
|
|
2
|
+
* Git history `IRSource` (§11.6/§11.7) — an `IRSource`, not a `LanguageAdapter`: one write path, no un-provenanced rows. Everything is R0; DEC-019 caps confidence at 0.5 and §11A.5 caps any finding at Class C — co-change is evidence about people, not code.
|
|
3
|
+
* Precision over recall: merge commits excluded from co-change (not from revert resolution below), large commits excluded, only explicit-revert trailers become incidents.
|
|
4
|
+
* `resolveCommitBySha` recovers reverts the primary index misses (6/9 real reverts, 5 repos, needed it); a genuinely-gone target is disclosed via `unresolved`, never dropped (rule 7).
|
|
56
5
|
*/
|
|
57
6
|
import { type IRSource } from "@descryy/ir";
|
|
58
7
|
import { type Commit, type HistoryOptions } from "./history.ts";
|
|
59
8
|
export declare const GIT_SOURCE_ID = "git-history";
|
|
60
9
|
export declare const GIT_SOURCE_VERSION = "0.1.0";
|
|
61
|
-
/**
|
|
62
|
-
* `
|
|
63
|
-
*
|
|
64
|
-
* Emitting both directions would double the edge count and make the pair count
|
|
65
|
-
* twice in any per-edge aggregate. The cost is that a caller must traverse it
|
|
66
|
-
* undirected — `direction: "both"` — and forgetting that yields a *missing*
|
|
67
|
-
* edge, which is a disclosed gap rather than a wrong answer. That asymmetry is
|
|
68
|
-
* why this is the safe default and not the convenient one.
|
|
69
|
-
*/
|
|
10
|
+
/** `CHANGES_WITH` is symmetric, stored one direction only — a caller must
|
|
11
|
+
* traverse `direction: "both"`, or gets a disclosed missing edge, not a wrong one. */
|
|
70
12
|
export declare const UNDIRECTED_EDGE_TYPES: readonly ["CHANGES_WITH"];
|
|
71
13
|
export interface GitSourceOptions extends HistoryOptions {
|
|
72
14
|
readonly repo: string;
|
|
73
15
|
readonly cwd: string;
|
|
74
|
-
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* **Provisional.** The architecture's own illustration is that 18x co-change
|
|
78
|
-
* is a warning and 2x is noise, which fixes the shape of the threshold but not
|
|
79
|
-
* its value; §32's tuning register has no number for it either. 5 is a
|
|
80
|
-
* defensible floor for a repo with a few hundred commits and is expected to
|
|
81
|
-
* move once measured. See DEC-033.
|
|
82
|
-
*/
|
|
16
|
+
/** Minimum times two files must co-change before an edge is emitted.
|
|
17
|
+
* Provisional — 5 is a defensible floor, expected to move once measured (DEC-033). */
|
|
83
18
|
readonly minSupport?: number;
|
|
84
|
-
/**
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* Support alone over-reports the files that change constantly: a config file
|
|
88
|
-
* touched in half of all commits co-occurs with everything. Confidence is what
|
|
89
|
-
* separates "coupled" from "always busy".
|
|
90
|
-
*/
|
|
19
|
+
/** Minimum `support / timesFileChanged` — support alone over-reports files
|
|
20
|
+
* that change constantly; this separates "coupled" from "always busy". */
|
|
91
21
|
readonly minConfidence?: number;
|
|
92
22
|
}
|
|
93
23
|
export declare function revertedShaOf(commit: Commit): string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../../src/sources/git/source.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../../src/sources/git/source.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAQL,KAAK,QAAQ,EAGd,MAAM,aAAa,CAAC;AAErB,OAAO,EAKL,KAAK,MAAM,EACX,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AAGtB,eAAO,MAAM,aAAa,gBAAgB,CAAC;AAC3C,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAG1C;uFACuF;AACvF,eAAO,MAAM,qBAAqB,2BAA4B,CAAC;AAE/D,MAAM,WAAW,gBAAiB,SAAQ,cAAc;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;2FACuF;IACvF,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;+EAC2E;IAC3E,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAWD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG3D;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,QAAQ,CAkUnE"}
|
|
@@ -1,58 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* that split exists: history is a producer of IR with no parser, no language and
|
|
6
|
-
* no resolution beyond R0, and without the narrower interface it would need a
|
|
7
|
-
* second write path — and a second write path is how un-provenanced rows reach
|
|
8
|
-
* storage.
|
|
9
|
-
*
|
|
10
|
-
* ## Everything here is R0, and that is not a formality
|
|
11
|
-
*
|
|
12
|
-
* Co-change is not code analysis. It observes that two files were edited in the
|
|
13
|
-
* same commit, which is evidence about *people*, not about program structure.
|
|
14
|
-
* R0's confidence ceiling (DEC-019) therefore caps every edge this source emits
|
|
15
|
-
* at 0.5, and §11A.5's reliability cap makes any finding resting on one Class C
|
|
16
|
-
* — a behavioural prediction that must be live-confirmed or dropped. That is the
|
|
17
|
-
* correct treatment: "these two files usually change together" is a hint for a
|
|
18
|
-
* human, never a claim about what breaks.
|
|
19
|
-
*
|
|
20
|
-
* ## Precision over recall, applied three times
|
|
21
|
-
*
|
|
22
|
-
* 1. **Merge commits are excluded from co-change.** A merge's file list is the
|
|
23
|
-
* union of both branches, so counting it would report every file in a large
|
|
24
|
-
* merge as coupled to every other. This exclusion is scoped to co-change —
|
|
25
|
-
* it does **not** apply to resolving what a revert names (see below): a
|
|
26
|
-
* revert of "Merge pull request #N" is a real incident whose target
|
|
27
|
-
* happens to be a merge commit, and excluding it from co-change is not a
|
|
28
|
-
* reason to also make it unresolvable as an incident.
|
|
29
|
-
* 2. **Large commits are excluded.** A commit touching hundreds of files is a
|
|
30
|
-
* reformat or a dependency bump; including it adds O(n²) edges that mean
|
|
31
|
-
* nothing.
|
|
32
|
-
* 3. **Only explicit reverts become incidents.** A commit whose message merely
|
|
33
|
-
* contains "fix" is not evidence of an incident. `git revert` writes a
|
|
34
|
-
* machine-generated `This reverts commit <sha>.` line, and that is the only
|
|
35
|
-
* signal used.
|
|
36
|
-
*
|
|
37
|
-
* ## Resolving what a revert names
|
|
38
|
-
*
|
|
39
|
-
* `readHistory` indexes commits reachable from `HEAD`, minus merges. A revert
|
|
40
|
-
* commit's target sha can miss that index for two reasons that have nothing to
|
|
41
|
-
* do with whether the incident is real: the target is a merge commit (excluded
|
|
42
|
-
* above), or the target was never merged as itself — a squash/rebase-merge
|
|
43
|
-
* workflow (GitHub's default) discards the original commits and only the
|
|
44
|
-
* squashed commit survives on `HEAD`, so "Revert PR #N" names a sha that is
|
|
45
|
-
* either real-but-unreachable (still sitting on an abandoned branch) or
|
|
46
|
-
* genuinely gone (garbage-collected after the branch was deleted). Measured
|
|
47
|
-
* against 5 real repos, 6 of 9 real reverts fell into these two buckets and
|
|
48
|
-
* were silently dropped by a naive index lookup.
|
|
49
|
-
*
|
|
50
|
-
* `resolveCommitBySha` is the fallback: it goes straight to the object
|
|
51
|
-
* database (`git cat-file` / `git diff-tree`), which enforces neither
|
|
52
|
-
* constraint `readHistory` applies. It resolves the merge case and the
|
|
53
|
-
* unreachable-but-present case. Only the genuinely-gone case still fails, and
|
|
54
|
-
* that failure is disclosed via `unresolved` (below) rather than dropped with
|
|
55
|
-
* no trace — this is the fallback CLAUDE.md rule 7 requires labelling.
|
|
2
|
+
* Git history `IRSource` (§11.6/§11.7) — an `IRSource`, not a `LanguageAdapter`: one write path, no un-provenanced rows. Everything is R0; DEC-019 caps confidence at 0.5 and §11A.5 caps any finding at Class C — co-change is evidence about people, not code.
|
|
3
|
+
* Precision over recall: merge commits excluded from co-change (not from revert resolution below), large commits excluded, only explicit-revert trailers become incidents.
|
|
4
|
+
* `resolveCommitBySha` recovers reverts the primary index misses (6/9 real reverts, 5 repos, needed it); a genuinely-gone target is disclosed via `unresolved`, never dropped (rule 7).
|
|
56
5
|
*/
|
|
57
6
|
import { edgeId, fileQsp, nodeId, } from "@descryy/ir";
|
|
58
7
|
import { gitHead, isGitRepository, readHistory, resolveCommitBySha, } from "./history.js";
|
|
@@ -60,24 +9,11 @@ import { detectIncidents } from "./incidents.js";
|
|
|
60
9
|
export const GIT_SOURCE_ID = "git-history";
|
|
61
10
|
export const GIT_SOURCE_VERSION = "0.1.0";
|
|
62
11
|
const PRODUCED_BY = `${GIT_SOURCE_ID}@${GIT_SOURCE_VERSION}`;
|
|
63
|
-
/**
|
|
64
|
-
* `
|
|
65
|
-
*
|
|
66
|
-
* Emitting both directions would double the edge count and make the pair count
|
|
67
|
-
* twice in any per-edge aggregate. The cost is that a caller must traverse it
|
|
68
|
-
* undirected — `direction: "both"` — and forgetting that yields a *missing*
|
|
69
|
-
* edge, which is a disclosed gap rather than a wrong answer. That asymmetry is
|
|
70
|
-
* why this is the safe default and not the convenient one.
|
|
71
|
-
*/
|
|
12
|
+
/** `CHANGES_WITH` is symmetric, stored one direction only — a caller must
|
|
13
|
+
* traverse `direction: "both"`, or gets a disclosed missing edge, not a wrong one. */
|
|
72
14
|
export const UNDIRECTED_EDGE_TYPES = ["CHANGES_WITH"];
|
|
73
|
-
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* `git revert` writes `This reverts commit <40 hex>.` into the body. Nothing
|
|
77
|
-
* else is trusted: matching on the word "fix" would classify ordinary work as an
|
|
78
|
-
* incident, and an `INCIDENT` node is a durable, earned fact (DEC-017) that
|
|
79
|
-
* outlives every rebuild.
|
|
80
|
-
*/
|
|
15
|
+
/** Detects a revert and the commit it reverted, via `git revert`'s machine-written
|
|
16
|
+
* trailer only — an `INCIDENT` node is a durable, earned fact (DEC-017). */
|
|
81
17
|
const REVERTS = /This reverts commit ([0-9a-f]{40})/;
|
|
82
18
|
export function revertedShaOf(commit) {
|
|
83
19
|
const match = REVERTS.exec(commit.body);
|
|
@@ -92,18 +28,15 @@ export function createGitSource(options) {
|
|
|
92
28
|
async emit(ctx) {
|
|
93
29
|
const repo = options.repo || ctx.root.repo;
|
|
94
30
|
const cwd = options.cwd;
|
|
95
|
-
// INCIDENT
|
|
96
|
-
// repo-scoped, and `scopeOf` picks between them per type — this source does
|
|
97
|
-
// not choose, and must not.
|
|
31
|
+
// INCIDENT/FIX_PATTERN are workspace-scoped (DEC-054), FILE repo-scoped.
|
|
98
32
|
const scope = { repo, workspace: ctx.root.workspace };
|
|
99
33
|
if (!(await isGitRepository(cwd))) {
|
|
100
|
-
// Not an error
|
|
101
|
-
// has nothing to say, and an empty batch says exactly that.
|
|
34
|
+
// Not an error — a repo with no history has nothing to say here.
|
|
102
35
|
return emptyBatch(repo, ctx.root.workspace, ctx.root.commitSha);
|
|
103
36
|
}
|
|
104
37
|
const commits = await readHistory(cwd, options);
|
|
105
38
|
const head = await gitHead(cwd);
|
|
106
|
-
//
|
|
39
|
+
// Co-change (§11.7).
|
|
107
40
|
const fileChanges = new Map();
|
|
108
41
|
const pairs = new Map();
|
|
109
42
|
const touched = new Set();
|
|
@@ -128,28 +61,17 @@ export function createGitSource(options) {
|
|
|
128
61
|
}
|
|
129
62
|
}
|
|
130
63
|
}
|
|
131
|
-
//
|
|
64
|
+
// Incidents (§11.6).
|
|
132
65
|
const maxFilesPerCommit = options.maxFilesPerCommit ?? 50;
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
// declared: the trailer `git revert` writes, the `Revert "…"` subject a
|
|
136
|
-
// person or GitHub's own button writes, and a `Fixes #123` a developer
|
|
137
|
-
// wrote to say something was broken. Nothing here reads "fix" out of
|
|
138
|
-
// prose; see that module's header for why an EARNED node cannot be minted
|
|
139
|
-
// from an inference.
|
|
66
|
+
// Three declared mechanisms (incidents.ts): a revert trailer, a `Revert
|
|
67
|
+
// "…"` subject, or a `Fixes #123` — never inferred from prose like "fix".
|
|
140
68
|
const detected = detectIncidents(commits);
|
|
141
69
|
const incidents = [...detected.incidents];
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
// hang an INCIDENT on. Disclosed via `unresolved`, never dropped with no
|
|
145
|
-
// trace (CLAUDE.md rule 7).
|
|
70
|
+
// Real per the commit's own message but unresolvable to a commit — disclosed
|
|
71
|
+
// via `unresolved`, never silently dropped (rule 7).
|
|
146
72
|
const unresolvedReverts = [];
|
|
147
73
|
for (const trailer of detected.unresolvedTrailers) {
|
|
148
|
-
// Not in the primary
|
|
149
|
-
// object database directly before giving up — see the module doc's
|
|
150
|
-
// "Resolving what a revert names". `detectIncidents` is synchronous and
|
|
151
|
-
// cannot do this, which is why it hands the case back rather than
|
|
152
|
-
// refusing it itself.
|
|
74
|
+
// Not in the primary index — try the object database (see module doc).
|
|
153
75
|
const reverted = await resolveCommitBySha(cwd, trailer.revertedSha, maxFilesPerCommit);
|
|
154
76
|
if (reverted === null) {
|
|
155
77
|
unresolvedReverts.push({
|
|
@@ -168,9 +90,8 @@ export function createGitSource(options) {
|
|
|
168
90
|
correlatedPaths: [...new Set(reverted.changes.map((c) => c.path))].sort(),
|
|
169
91
|
});
|
|
170
92
|
}
|
|
171
|
-
// A
|
|
172
|
-
//
|
|
173
|
-
// is not an identity — so these are refusals as detected.
|
|
93
|
+
// A quoted subject not found (or found twice) — a subject isn't an
|
|
94
|
+
// identity, so unresolvable out of band, unlike a sha.
|
|
174
95
|
for (const refusal of detected.refusals) {
|
|
175
96
|
const fix = commits.find((c) => c.sha === refusal.fixSha);
|
|
176
97
|
if (fix === undefined)
|
|
@@ -182,7 +103,7 @@ export function createGitSource(options) {
|
|
|
182
103
|
for (const path of found.correlatedPaths)
|
|
183
104
|
touched.add(path);
|
|
184
105
|
}
|
|
185
|
-
//
|
|
106
|
+
// Nodes.
|
|
186
107
|
const nodes = [];
|
|
187
108
|
const sourceFiles = [...touched].sort();
|
|
188
109
|
for (const path of sourceFiles) {
|
|
@@ -192,26 +113,16 @@ export function createGitSource(options) {
|
|
|
192
113
|
name: path.split("/").pop() ?? path,
|
|
193
114
|
file: path,
|
|
194
115
|
range: null,
|
|
195
|
-
//
|
|
196
|
-
//
|
|
197
|
-
// that has no business making one (DEC-026).
|
|
116
|
+
// Guessing language from the extension would be a language decision
|
|
117
|
+
// made by a source with no business making one (DEC-026).
|
|
198
118
|
language: null,
|
|
199
119
|
producedBy: PRODUCED_BY,
|
|
200
120
|
resolution: 0,
|
|
201
121
|
attrs: { changeCount: fileChanges.get(path) ?? 0 },
|
|
202
122
|
});
|
|
203
123
|
}
|
|
204
|
-
/**
|
|
205
|
-
*
|
|
206
|
-
* saying `Fixes #7` are one defect fixed twice, not two defects. So the
|
|
207
|
-
* `INCIDENT` node is keyed and emitted once; the `FIX_PATTERN` and the
|
|
208
|
-
* `FIXED_BY` edge are per-fix.
|
|
209
|
-
*
|
|
210
|
-
* The issue form's qualified symbol path carries the repository even
|
|
211
|
-
* though `INCIDENT` is workspace-scoped (DEC-054), because `#123` in one
|
|
212
|
-
* repository is not `#123` in another and a bare number would collide two
|
|
213
|
-
* unrelated defects into one node across a linked workspace.
|
|
214
|
-
*/
|
|
124
|
+
/** One incident, multiple fixes — `INCIDENT` keyed and emitted once, `FIX_PATTERN`
|
|
125
|
+
* per-fix. Issue id carries the repo (DEC-054) so `#123` doesn't collide across repos. */
|
|
215
126
|
const incidentIdOf = (found) => found.incidentCommit !== null
|
|
216
127
|
? nodeId(scope, "INCIDENT", found.incidentCommit.sha, null)
|
|
217
128
|
: nodeId(scope, "INCIDENT", `issue:${repo}${found.issueRef ?? ""}`, null);
|
|
@@ -239,10 +150,7 @@ export function createGitSource(options) {
|
|
|
239
150
|
: {
|
|
240
151
|
id,
|
|
241
152
|
type: "INCIDENT",
|
|
242
|
-
//
|
|
243
|
-
// and must not imply it knows the issue's title, or even that
|
|
244
|
-
// the issue was filed as a defect — only that the developer who
|
|
245
|
-
// closed it said their commit fixed something.
|
|
153
|
+
// Issue reference only — no tracker is read, so no title or defect status is implied.
|
|
246
154
|
name: `${repo}${found.issueRef ?? ""}`,
|
|
247
155
|
file: null,
|
|
248
156
|
range: null,
|
|
@@ -275,13 +183,9 @@ export function createGitSource(options) {
|
|
|
275
183
|
},
|
|
276
184
|
});
|
|
277
185
|
}
|
|
278
|
-
// The fix commit is real
|
|
279
|
-
//
|
|
280
|
-
//
|
|
281
|
-
// FIXED_BY edge or any INCIDENT_CORRELATED edge, because none of those
|
|
282
|
-
// can be built without a resolved target. The gap is recorded below in
|
|
283
|
-
// `unresolved`, not implied by a node that silently has no incoming
|
|
284
|
-
// FIXED_BY edge.
|
|
186
|
+
// The fix commit is real, so it earns a FIX_PATTERN node — but no INCIDENT,
|
|
187
|
+
// FIXED_BY or INCIDENT_CORRELATED edge, since none can be built without a
|
|
188
|
+
// resolved target; the gap is recorded in `unresolved` instead.
|
|
285
189
|
for (const { fix } of unresolvedReverts) {
|
|
286
190
|
nodes.push({
|
|
287
191
|
id: nodeId(scope, "FIX_PATTERN", fix.sha, null),
|
|
@@ -295,7 +199,7 @@ export function createGitSource(options) {
|
|
|
295
199
|
attrs: { commitSha: fix.sha, revertedShaUnresolved: true },
|
|
296
200
|
});
|
|
297
201
|
}
|
|
298
|
-
//
|
|
202
|
+
// Edges.
|
|
299
203
|
const nodeIds = new Set(nodes.map((n) => n.id));
|
|
300
204
|
const edges = [];
|
|
301
205
|
const unresolved = [];
|
|
@@ -313,9 +217,8 @@ export function createGitSource(options) {
|
|
|
313
217
|
to: nodeId(scope, "FILE", fileQsp(b), null),
|
|
314
218
|
type: "CHANGES_WITH",
|
|
315
219
|
resolution: 0,
|
|
316
|
-
//
|
|
317
|
-
//
|
|
318
|
-
// graph shows that history was capped rather than that it was weak.
|
|
220
|
+
// Raw ratio passed through; the Normaliser's R0 clamp is recorded,
|
|
221
|
+
// showing history was capped rather than weak.
|
|
319
222
|
confidence,
|
|
320
223
|
producedBy: PRODUCED_BY,
|
|
321
224
|
attrs: {
|
|
@@ -339,9 +242,8 @@ export function createGitSource(options) {
|
|
|
339
242
|
attrs: { commitSha: fix.sha, refusalClass: "capability-gap" },
|
|
340
243
|
});
|
|
341
244
|
}
|
|
342
|
-
//
|
|
343
|
-
//
|
|
344
|
-
// the second write says nothing the first did not.
|
|
245
|
+
// Per incident, not per fix — two commits closing one issue would
|
|
246
|
+
// otherwise write the same file edge twice.
|
|
345
247
|
const correlated = new Set();
|
|
346
248
|
for (const found of incidents) {
|
|
347
249
|
const incidentId = incidentIdOf(found);
|
|
@@ -391,9 +293,7 @@ export function createGitSource(options) {
|
|
|
391
293
|
});
|
|
392
294
|
}
|
|
393
295
|
}
|
|
394
|
-
// Deterministic ordering
|
|
395
|
-
// byte-identical batch, or the store's content hash moves for no reason
|
|
396
|
-
// and the Step 6 determinism proof stops meaning anything.
|
|
296
|
+
// Deterministic ordering — two runs must produce a byte-identical batch.
|
|
397
297
|
nodes.sort((a, b) => a.id.localeCompare(b.id));
|
|
398
298
|
edges.sort((a, b) => edgeId(a.from, a.to, a.type).localeCompare(edgeId(b.from, b.to, b.type)));
|
|
399
299
|
unresolved.sort((a, b) => `${a.fromNodeId}${a.rawTarget}`.localeCompare(`${b.fromNodeId}${b.rawTarget}`));
|