@event4u/agent-config 14.16.0 → 14.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +83 -210
  5. package/README.md +1 -1
  6. package/dist/agent-src/commands/analyze/inbox.md +172 -6
  7. package/dist/agent-src/commands/fix/commit-messages.md +336 -0
  8. package/dist/agent-src/commands/fix.md +5 -3
  9. package/dist/agent-src/rules/commit-conventions.md +1 -1
  10. package/dist/agent-src/skills/aws-infrastructure/SKILL.md +41 -0
  11. package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +234 -4
  12. package/dist/agent-src/skills/terraform/SKILL.md +29 -0
  13. package/dist/agent-src/skills/threat-modeling/data/reasoning.csv +1 -0
  14. package/dist/agent-src/skills/threat-modeling/data/surfaces.csv +1 -0
  15. package/dist/agent-src/skills/threat-modeling/data/threats.csv +5 -0
  16. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  17. package/dist/cli-delegate/cmd_explain.js +24 -112
  18. package/dist/discovery/deprecation-report.md +1 -1
  19. package/dist/discovery/discovery-manifest.json +42 -16
  20. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  21. package/dist/discovery/discovery-manifest.summary.md +3 -3
  22. package/dist/discovery/dormancy-report.md +1 -1
  23. package/dist/discovery/orphan-report.md +1 -1
  24. package/dist/discovery/packs.json +6 -5
  25. package/dist/discovery/trust-report.md +2 -2
  26. package/dist/discovery/workspaces.json +5 -4
  27. package/dist/mcp/registry-manifest.json +3 -3
  28. package/dist/mcp/server.json +2 -2
  29. package/package.json +1 -1
  30. package/src/config/web-launch-readiness.json +1 -1
  31. package/src/scripts/_cli/explain_last/index.ts +1 -1
  32. package/src/scripts/_cli/explain_last/memory.ts +8 -104
  33. package/src/scripts/check_artefact_count_messaging.ts +9 -0
  34. package/src/scripts/check_release_highlights.ts +77 -4
  35. package/src/scripts/check_web_launch_readiness.ts +295 -15
  36. package/src/scripts/measure_release_mix.ts +384 -0
  37. package/src/scripts/release_mix_taxonomy.json +172 -0
  38. package/src/scripts/attest_artifact.ts +0 -193
@@ -360,7 +360,7 @@
360
360
  },
361
361
  {
362
362
  "category": "command",
363
- "checksum": "sha256:566e4d523e131bdf5e0a28a5bf0c544805956c646b03d2a45a9061c8268d4d49",
363
+ "checksum": "sha256:acfd0bdc3251429e8f418b6d9f3e32a26ba85942266a2248c053288c34b4f429",
364
364
  "install": {
365
365
  "default": true,
366
366
  "removable": false
@@ -1057,12 +1057,12 @@
1057
1057
  },
1058
1058
  {
1059
1059
  "category": "command",
1060
- "checksum": "sha256:8cd5692abb4cbaec5526cc650ad88a7429a5dcf1c921e80974bf46e5227afc31",
1060
+ "checksum": "sha256:598e0006286c50059835114af326c888669fadccc34218bd8aeb7bc60d319b9f",
1061
1061
  "install": {
1062
1062
  "default": true,
1063
1063
  "removable": false
1064
1064
  },
1065
- "intent": "Fix-workflow dispatcher — ci, pr-comments, pr-comments-loop, refs, seeder, portability, comments, quality",
1065
+ "intent": "Fix-workflow dispatcher — ci, pr-comments, pr-comments-loop, refs, seeder, portability, comments, commit-messages, quality",
1066
1066
  "lifecycle": "active",
1067
1067
  "name": "fix",
1068
1068
  "pack": "engineering-base",
@@ -1079,6 +1079,7 @@
1079
1079
  "fix-seeder",
1080
1080
  "fix-portability",
1081
1081
  "fix-comments",
1082
+ "fix-commit-messages",
1082
1083
  "fix-quality",
1083
1084
  "fix-route"
1084
1085
  ],
@@ -1118,6 +1119,31 @@
1118
1119
  "agent-config-maintainer"
1119
1120
  ]
1120
1121
  },
1122
+ {
1123
+ "category": "command",
1124
+ "checksum": "sha256:f7bfaa1534906c98194154aad1f8ea6c0f0ade94a3e6da884b4669d7058b7443",
1125
+ "install": {
1126
+ "default": true,
1127
+ "removable": false
1128
+ },
1129
+ "lifecycle": "active",
1130
+ "name": "fix-commit-messages",
1131
+ "pack": "engineering-base",
1132
+ "packs": [
1133
+ "meta"
1134
+ ],
1135
+ "path": "src/domains/engineering-base/fix/commit-messages/command.md",
1136
+ "slug": "fix-commit-messages",
1137
+ "trust": {
1138
+ "confidence": "high",
1139
+ "human_review_required": false,
1140
+ "level": "core"
1141
+ },
1142
+ "visibility": "internal",
1143
+ "workspaces": [
1144
+ "agent-config-maintainer"
1145
+ ]
1146
+ },
1121
1147
  {
1122
1148
  "category": "command",
1123
1149
  "checksum": "sha256:380c991a9f4948ab9753e92fed18658db17b45893687164281205ae3885be34f",
@@ -5732,7 +5758,7 @@
5732
5758
  },
5733
5759
  {
5734
5760
  "category": "rule",
5735
- "checksum": "sha256:e78ad2e07a0c187fca461658b3d6a4d2c18bbf632e7075b2bceef64a462736fd",
5761
+ "checksum": "sha256:7f012a7428d4c4d0412dbb853bb64421ffeb420173a92e23a386afa0d5b62b4e",
5736
5762
  "install": {
5737
5763
  "default": true,
5738
5764
  "removable": false
@@ -8577,7 +8603,7 @@
8577
8603
  },
8578
8604
  {
8579
8605
  "category": "skill",
8580
- "checksum": "sha256:baa93744948e26b3677cb77144d491070ea63bf495191c8e66db7a9d44a26970",
8606
+ "checksum": "sha256:e58d69196c8e5c90fc9902a78a86fd3606284c6d471615fa9e69867efd13d004",
8581
8607
  "install": {
8582
8608
  "default": true,
8583
8609
  "removable": false
@@ -9281,7 +9307,7 @@
9281
9307
  },
9282
9308
  {
9283
9309
  "category": "skill",
9284
- "checksum": "sha256:9b25b8ff439cf3c9fd703d052f5f499a85dbf418110140a8d1d99720bb14594b",
9310
+ "checksum": "sha256:42a56536667e2d98e94404905831a02accb86dfe5844dc9499fe4e2abb2fbb93",
9285
9311
  "install": {
9286
9312
  "default": true,
9287
9313
  "removable": false
@@ -14149,7 +14175,7 @@
14149
14175
  },
14150
14176
  {
14151
14177
  "category": "skill",
14152
- "checksum": "sha256:f3b517e7641304ddb59aa87f889d13174bc7459f53b6482f39f3c29e82c676b6",
14178
+ "checksum": "sha256:04ca9b083907c4c44d3d73740a1e629d84ba3e689a9640250c93060b41646a7c",
14153
14179
  "install": {
14154
14180
  "default": true,
14155
14181
  "removable": false
@@ -14743,7 +14769,7 @@
14743
14769
  },
14744
14770
  {
14745
14771
  "category": "subagent",
14746
- "checksum": "sha256:d57dfc1457cf467402e4ee1187cd162cbb62ddecb35b101d6e1aae6e2f103baa",
14772
+ "checksum": "sha256:b455bc3b2ee4e2adadd5ed9e9b781068aaafda014304bf91a5574d26d543683d",
14747
14773
  "install": {
14748
14774
  "default": false,
14749
14775
  "removable": true
@@ -14760,7 +14786,7 @@
14760
14786
  "workspaces": []
14761
14787
  }
14762
14788
  ],
14763
- "checksum": "sha256:dd8fabe64f8d77c0d267127d1797192fba713fa8498e4b5883701c84fff20e6e",
14789
+ "checksum": "sha256:050eb71e8c64d4eae3c85c2691838794f9a436a1808835a8b388f2a3971250ac",
14764
14790
  "deprecations": [
14765
14791
  {
14766
14792
  "key": "tier",
@@ -14909,7 +14935,7 @@
14909
14935
  "reason": "scaffold template for ticket-bundle tickets (ADR-101); carries no runtime frontmatter — emit-tickets fills it in per ticket"
14910
14936
  }
14911
14937
  ],
14912
- "generated_at": "2026-09-04T03:43:39Z",
14938
+ "generated_at": "2026-09-05T05:33:47Z",
14913
14939
  "packs": [
14914
14940
  {
14915
14941
  "artefact_count": 128,
@@ -15658,7 +15684,7 @@
15658
15684
  },
15659
15685
  {
15660
15686
  "always_on": true,
15661
- "artefact_count": 300,
15687
+ "artefact_count": 301,
15662
15688
  "description": "Artefacts that maintain this package (agent-config itself).",
15663
15689
  "domain": "meta",
15664
15690
  "human_review_required": 0,
@@ -15674,7 +15700,7 @@
15674
15700
  "trust_level_default": "core",
15675
15701
  "trust_summary": {
15676
15702
  "advisory": 0,
15677
- "core": 298,
15703
+ "core": 299,
15678
15704
  "experimental": 2,
15679
15705
  "professional": 0,
15680
15706
  "restricted": 0
@@ -15765,27 +15791,27 @@
15765
15791
  "scanner_version": "de0a22b4ac4c",
15766
15792
  "stats": {
15767
15793
  "by_category": {
15768
- "command": 202,
15794
+ "command": 203,
15769
15795
  "rule": 120,
15770
15796
  "skill": 299,
15771
15797
  "subagent": 1,
15772
15798
  "template": 1
15773
15799
  },
15774
15800
  "by_lifecycle": {
15775
- "active": 605,
15801
+ "active": 606,
15776
15802
  "archived": 0,
15777
15803
  "deprecated": 0,
15778
15804
  "experimental": 18
15779
15805
  },
15780
15806
  "by_trust_level": {
15781
15807
  "advisory": 8,
15782
- "core": 490,
15808
+ "core": 491,
15783
15809
  "experimental": 23,
15784
15810
  "professional": 102,
15785
15811
  "restricted": 0
15786
15812
  },
15787
15813
  "documented_unassigned_count": 27,
15788
- "total_artefacts": 623,
15814
+ "total_artefacts": 624,
15789
15815
  "unassigned_count": 0
15790
15816
  },
15791
15817
  "unassigned": [],
@@ -1 +1 @@
1
- 39bbab4136c262fec6b632f6019ca5269b010e6a49c660c6325014a2e72e304f discovery-manifest.json
1
+ b6d912c7a07017329d09d59c8a57ec9facf284dee72f6cf0b1d5c05c88ac8c9f discovery-manifest.json
@@ -1,8 +1,8 @@
1
1
  # Discovery Manifest — Summary
2
2
 
3
- - Generated: `2026-09-04T03:43:39Z`
3
+ - Generated: `2026-09-05T05:33:47Z`
4
4
  - Scanner: `de0a22b4ac4c`
5
- - Artefacts: **623**
5
+ - Artefacts: **624**
6
6
  - Unassigned: **0**
7
7
 
8
8
  ## `engineering` — Engineering
@@ -106,7 +106,7 @@
106
106
 
107
107
  | Pack | Artefacts |
108
108
  |---|---|
109
- | `meta` — Meta | 300 |
109
+ | `meta` — Meta | 301 |
110
110
  | `memory` — Memory | 9 |
111
111
  | `analytics` — Analytics | 4 |
112
112
  | `product-reasoning` — Product Reasoning | 11 |
@@ -1,6 +1,6 @@
1
1
  # Discovery — Dormancy Report
2
2
 
3
- - Generated: `2026-09-04T03:43:39Z`
3
+ - Generated: `2026-09-05T05:33:47Z`
4
4
  - Window: **6 months** without a commit
5
5
 
6
6
  > Dormancy triggers **review, never auto-deprecation**
@@ -1,6 +1,6 @@
1
1
  # Discovery — Orphan Report
2
2
 
3
- - Generated: `2026-09-04T03:43:39Z`
3
+ - Generated: `2026-09-05T05:33:47Z`
4
4
  - Orphan artefacts: **0**
5
5
 
6
6
  > An orphan is an artefact whose declared pack has no other members.
@@ -1,6 +1,6 @@
1
1
  {
2
- "checksum": "sha256:dd8fabe64f8d77c0d267127d1797192fba713fa8498e4b5883701c84fff20e6e",
3
- "generated_at": "2026-09-04T03:43:39Z",
2
+ "checksum": "sha256:050eb71e8c64d4eae3c85c2691838794f9a436a1808835a8b388f2a3971250ac",
3
+ "generated_at": "2026-09-05T05:33:47Z",
4
4
  "packs": [
5
5
  {
6
6
  "always_on": false,
@@ -1367,7 +1367,7 @@
1367
1367
  },
1368
1368
  {
1369
1369
  "always_on": true,
1370
- "artefact_count": 300,
1370
+ "artefact_count": 301,
1371
1371
  "artefacts": [
1372
1372
  "src/agent-src/templates/agents/proposal.example.md",
1373
1373
  "src/domains/ai-video/image/analyse/command.md",
@@ -1396,6 +1396,7 @@
1396
1396
  "src/domains/engineering-base/fix/ci/command.md",
1397
1397
  "src/domains/engineering-base/fix/command.md",
1398
1398
  "src/domains/engineering-base/fix/comments/command.md",
1399
+ "src/domains/engineering-base/fix/commit-messages/command.md",
1399
1400
  "src/domains/engineering-base/fix/portability/command.md",
1400
1401
  "src/domains/engineering-base/fix/pr-comments-loop/command.md",
1401
1402
  "src/domains/engineering-base/fix/pr-comments/command.md",
@@ -1671,14 +1672,14 @@
1671
1672
  "src/skills/verify-repair-loop/SKILL.md"
1672
1673
  ],
1673
1674
  "by_lifecycle": {
1674
- "active": 299,
1675
+ "active": 300,
1675
1676
  "archived": 0,
1676
1677
  "deprecated": 0,
1677
1678
  "experimental": 1
1678
1679
  },
1679
1680
  "by_trust_level": {
1680
1681
  "advisory": 0,
1681
- "core": 298,
1682
+ "core": 299,
1682
1683
  "experimental": 2,
1683
1684
  "professional": 0,
1684
1685
  "restricted": 0
@@ -1,6 +1,6 @@
1
1
  # Discovery — Trust Report
2
2
 
3
- - Generated: `2026-09-04T03:43:39Z`
3
+ - Generated: `2026-09-05T05:33:47Z`
4
4
  - Workspaces tracked: **10**
5
5
  - Human-review-required artefacts: **3**
6
6
 
@@ -8,7 +8,7 @@
8
8
 
9
9
  | Workspace | core | professional | experimental | advisory | restricted |
10
10
  |---|---|---|---|---|---|
11
- | `agent-config-maintainer` | 330 | 0 | 3 | 0 | 0 |
11
+ | `agent-config-maintainer` | 331 | 0 | 3 | 0 | 0 |
12
12
  | `construction` | 27 | 0 | 0 | 0 | 0 |
13
13
  | `engineering` | 201 | 62 | 4 | 0 | 0 |
14
14
  | `finance` | 30 | 4 | 0 | 1 | 0 |
@@ -1,6 +1,6 @@
1
1
  {
2
- "checksum": "sha256:dd8fabe64f8d77c0d267127d1797192fba713fa8498e4b5883701c84fff20e6e",
3
- "generated_at": "2026-09-04T03:43:39Z",
2
+ "checksum": "sha256:050eb71e8c64d4eae3c85c2691838794f9a436a1808835a8b388f2a3971250ac",
3
+ "generated_at": "2026-09-05T05:33:47Z",
4
4
  "scanner_version": "de0a22b4ac4c",
5
5
  "workspaces": [
6
6
  {
@@ -648,7 +648,7 @@
648
648
  ]
649
649
  },
650
650
  {
651
- "artefact_count": 324,
651
+ "artefact_count": 325,
652
652
  "default_packs": [
653
653
  "meta",
654
654
  "memory",
@@ -661,7 +661,7 @@
661
661
  "optional_packs": [],
662
662
  "packs": [
663
663
  {
664
- "artefact_count": 300,
664
+ "artefact_count": 301,
665
665
  "artefacts": [
666
666
  "src/agent-src/templates/agents/proposal.example.md",
667
667
  "src/domains/ai-video/image/analyse/command.md",
@@ -690,6 +690,7 @@
690
690
  "src/domains/engineering-base/fix/ci/command.md",
691
691
  "src/domains/engineering-base/fix/command.md",
692
692
  "src/domains/engineering-base/fix/comments/command.md",
693
+ "src/domains/engineering-base/fix/commit-messages/command.md",
693
694
  "src/domains/engineering-base/fix/portability/command.md",
694
695
  "src/domains/engineering-base/fix/pr-comments-loop/command.md",
695
696
  "src/domains/engineering-base/fix/pr-comments/command.md",
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "discovery": {
3
- "artefact_count": 623,
3
+ "artefact_count": 624,
4
4
  "scanner_version": "de0a22b4ac4c"
5
5
  },
6
- "generated_at": "2026-09-04",
6
+ "generated_at": "2026-09-05",
7
7
  "package": {
8
8
  "description": "Governed skills, rules and commands for AI coding tools (Claude Code, Cursor, Windsurf, Copilot) \u2014 every claim machine-checked, including the counts in these badges.",
9
9
  "homepage": "https://event4u-app.github.io/agent-config",
10
10
  "name": "@event4u/agent-config",
11
11
  "repository": "https://github.com/event4u-app/agent-config",
12
- "version": "14.16.0"
12
+ "version": "14.17.0"
13
13
  },
14
14
  "registries": [
15
15
  {
@@ -9,12 +9,12 @@
9
9
  "transport": {
10
10
  "type": "stdio"
11
11
  },
12
- "version": "14.16.0"
12
+ "version": "14.17.0"
13
13
  }
14
14
  ],
15
15
  "repository": {
16
16
  "source": "github",
17
17
  "url": "https://github.com/event4u-app/agent-config"
18
18
  },
19
- "version": "14.16.0"
19
+ "version": "14.17.0"
20
20
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@event4u/agent-config",
3
3
  "mcpName": "io.github.event4u-app/agent-config",
4
- "version": "14.16.0",
4
+ "version": "14.17.0",
5
5
  "description": "Governed skills, rules and commands for AI coding tools (Claude Code, Cursor, Windsurf, Copilot) — every claim machine-checked, including the counts in these badges.",
6
6
  "license": "MIT",
7
7
  "private": false,
@@ -165,7 +165,7 @@
165
165
  "rule": "The external corpus is a STUDY OBJECT and a per-defect harvest source. Its rule set is not imported. Rules enter ONE AT A TIME, each against a named defect, each carrying its own remediation and verification.",
166
166
  "why": "An imported rule set arrives with its authors' assumptions about site type, jurisdiction and stack, and none of those is checked on arrival. The failure is silent: the skill grows to N checks, each individually plausible, and the conditional axis this file exists to enforce is the first thing a bulk import flattens. One-at-a-time keeps the axis honest because every entry has to answer `applies_to` before it lands.",
167
167
  "ceiling": 50,
168
- "ceiling_enforced_by": "tests/scripts/web_launch_readiness_config.test.ts asserts checks.length < 50. Currently 7."
168
+ "ceiling_enforced_by": "tests/scripts/web_launch_readiness_config.test.ts asserts checks.length < 50. The live count is NOT retyped here: a number a human retypes on every ledger edit drifts, and this field had said 7 while `checks` held 9. Read `checks.length`; the ceiling is the only number this row owns."
169
169
  },
170
170
  "regions": {
171
171
  "_comment": "Region axis (road-to-web-launch-readiness 2.3). LEGAL-ROW CONTRACT: any row here or in `checks` whose `why` names a statute MUST carry `authority` (the citation and where it can be read) and `review_by` (the ISO date it must be re-read by); `authority` and `review_by` travel together, so a citation moved out of prose into `authority` stays dated; and a lapsed `review_by` FAILS the loader rather than warning, because a date nothing reads is a comment. Enforced by legalRowViolations() in src/scripts/check_web_launch_readiness.ts, which loadConfig() calls before returning. Separate from site_types because it answers a different question: site_types decides WHETHER a check applies, regions decides HOW SEVERELY. A DE-targeted site owes an Impressum and a Datenschutzerklaerung by law -- the citations sit in the escalation's `authority` field, dated, rather than in prose, which is what the `ddg-citation-authority` decision of 2026-09-03 settled -- so `required-legal-pages` is critical there and situational elsewhere -- the same check, a different tier. Modelled as a tier ESCALATION rather than as a second applies_to list, because a legal page is not more or less applicable in Germany, it is more or less optional.",
@@ -144,7 +144,7 @@ export function build_trace(
144
144
  inputs: _inputs.build(project_root),
145
145
  route: _route.build(project_root, state),
146
146
  council: _council.build(project_root, state_file),
147
- memory: _memory.build(project_root, state),
147
+ memory: _memory.build(state),
148
148
  pack: _inputs.build_pack(project_root),
149
149
  assumptions: _assumptions.build(state),
150
150
  halt: _halt.build(state),
@@ -2,20 +2,20 @@
2
2
  * Resolve the `memory` why-slot for the trace.
3
3
  *
4
4
  * Ported from the retired Python `src/scripts/_cli/explain_last/memory.py` (ADR-200).
5
- * Behaviour pins the historical contract exactly — same two sources, same
6
- * coercion order, same `float()` semantics, same `None`-on-empty branch.
7
- * No behaviour changes.
5
+ * The coercion order, the `float()` semantics and the `None`-on-empty branch
6
+ * still pin that historical contract. The second source the port carried — a
7
+ * sidecar whose only documented producer was the Layer-2 memory-MCP
8
+ * integration — does not, because
9
+ * `docs/decisions/ADR-094-agent-memory-layer-removal.md` removed that layer
10
+ * and rejected leaving its surfaces inert. Nothing in the tree ever wrote it.
8
11
  *
9
- * Two sources are consulted:
12
+ * One source is consulted:
10
13
  *
11
14
  * - `state.memory[]` — the work-engine writes per-run memory hits here
12
15
  * during the `memory` step. Each entry carries `{entry_id, hit_score,
13
16
  * used_in}` already shaped to the trace contract.
14
- * - `<root>/.agent-memory/hits.jsonl` — optional sidecar produced by the
15
- * memory-MCP integration. Filtered to entries tagged with the run id
16
- * when present.
17
17
  *
18
- * Returns `null` when neither source produced a non-empty list (the schema
18
+ * Returns `null` when that source produced no non-empty list (the schema
19
19
  * accepts a null memory slot so the renderer can drop the section cleanly).
20
20
  *
21
21
  * Parity note (ADR-200): Python's `hit_score = float(...)` always yields a
@@ -23,9 +23,6 @@
23
23
  * The twin carries it as a `PyFloat` marker so the downstream JSON
24
24
  * serializer (and the section renderer's `:.2f`) stays byte-identical.
25
25
  */
26
- import * as fs from 'node:fs';
27
- import * as path from 'node:path';
28
-
29
26
  import { scrub_string } from './scrubber.js';
30
27
 
31
28
  /**
@@ -37,8 +34,6 @@ export class PyFloat {
37
34
  constructor(readonly value: number) {}
38
35
  }
39
36
 
40
- const MEMORY_SIDECAR = path.join('.agent-memory', 'hits.jsonl');
41
-
42
37
  /** Python truthiness (empty string / 0 / null / empty container falsy). */
43
38
  function _pyTruthy(value: unknown): boolean {
44
39
  if (value === null || value === undefined) {
@@ -132,100 +127,9 @@ function _from_state(state: Record<string, unknown>): Record<string, unknown>[]
132
127
  return entries;
133
128
  }
134
129
 
135
- /**
136
- * Python `str.splitlines()` (no args). Splits on the Python line-boundary
137
- * set (`\n \r \r\n \v \f \x1c \x1d \x1e \x85 
 
`) and emits no
138
- * trailing empty element when the string ends on a break.
139
- */
140
- function _splitlines(s: string): string[] {
141
- if (s === '') {
142
- return [];
143
- }
144
- const breaks = new Set([
145
- '\n', '\r', '\v', '\f',
146
- '\x1c', '\x1d', '\x1e', '\x85',
147
- '
', '
',
148
- ]);
149
- const out: string[] = [];
150
- let cur = '';
151
- for (let i = 0; i < s.length; i += 1) {
152
- const ch = s[i] as string;
153
- if (ch === '\r' && s[i + 1] === '\n') {
154
- out.push(cur);
155
- cur = '';
156
- i += 1;
157
- continue;
158
- }
159
- if (breaks.has(ch)) {
160
- out.push(cur);
161
- cur = '';
162
- continue;
163
- }
164
- cur += ch;
165
- }
166
- if (cur !== '') {
167
- out.push(cur);
168
- }
169
- return out;
170
- }
171
-
172
- function _from_sidecar(project_root: string, run_id: string | null): Record<string, unknown>[] {
173
- const p = path.join(project_root, MEMORY_SIDECAR);
174
- if (!fs.existsSync(p)) {
175
- return [];
176
- }
177
- const entries: Record<string, unknown>[] = [];
178
- let content: string;
179
- try {
180
- content = fs.readFileSync(p, 'utf-8');
181
- } catch {
182
- return [];
183
- }
184
- for (let line of _splitlines(content)) {
185
- line = line.trim();
186
- if (!line) {
187
- continue;
188
- }
189
- let raw: unknown;
190
- try {
191
- raw = JSON.parse(line);
192
- } catch {
193
- continue; // json.JSONDecodeError → skip line
194
- }
195
- if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
196
- continue;
197
- }
198
- const rawDict = raw as Record<string, unknown>;
199
- // if run_id and raw.get("run_id") not in (None, run_id): continue
200
- if (run_id) {
201
- const got = rawDict.run_id ?? null;
202
- if (got !== null && got !== run_id) {
203
- continue;
204
- }
205
- }
206
- const entry = _coerce_entry(rawDict);
207
- if (entry !== null) {
208
- entries.push(entry);
209
- }
210
- }
211
- return entries;
212
- }
213
-
214
130
  export function build(
215
- project_root: string,
216
131
  state: Record<string, unknown>,
217
132
  ): Record<string, unknown>[] | null {
218
- // run_id = (state.get("input") or {}).get("data", {}).get("id")
219
- const input = _pyTruthy(state.input) ? (state.input as Record<string, unknown>) : {};
220
- const dataRaw = 'data' in input ? input.data : {};
221
- const data =
222
- typeof dataRaw === 'object' && dataRaw !== null && !Array.isArray(dataRaw)
223
- ? (dataRaw as Record<string, unknown>)
224
- : {};
225
- const run_id = data.id;
226
133
  const entries = _from_state(state);
227
- entries.push(
228
- ..._from_sidecar(project_root, typeof run_id === 'string' ? run_id : null),
229
- );
230
134
  return entries.length > 0 ? entries : null;
231
135
  }
@@ -288,6 +288,15 @@ export function anchor_coverage_gaps(root: string = ROOT): CoverageGap[] {
288
288
  const allowed = ANCHOR_KINDS[kind] ?? [kind];
289
289
  for (let i = 0; i < lines.length; i++) {
290
290
  const line = lines[i]!;
291
+ // The dated-measurement marker is honoured HERE too, and it was
292
+ // not. `scan_text` skipped a marked line while this pass still
293
+ // demanded an anchor for it, so a figure the gate's own charter
294
+ // excludes — a point-in-time measurement, not a live total —
295
+ // could be silenced on value and never on coverage. An anchor is
296
+ // exactly the wrong repair for that line: `update_counts` would
297
+ // rewrite a recorded measurement to today's number, which is the
298
+ // falsification the marker's own docstring forbids.
299
+ if (line.includes(DATED_MEASUREMENT_MARKER)) continue;
291
300
  const re = new RegExp(pattern.source, pattern.flags);
292
301
  if (!re.test(line)) continue;
293
302
  const anchored = anchors.some(