@olegkoval/agent-skills 1.62.0 → 1.62.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.
@@ -53,13 +53,19 @@ const preamble = [
53
53
  // hardRuleCorroborated is likewise gone from the current file and kept in this
54
54
  // list for the same reason: an older workflow.js calls it from isHardRule.
55
55
  ...['titleTokens', 'sameIssue', 'nearbyLines', 'spanWithinWindow', 'hardRuleCorroborated',
56
- 'isHardRule', 'longest', 'mergeFindings', 'dedup', 'shouldVerify'].map(n => {
57
- try { return lift(n) } catch { return `function ${n}() { throw new Error('${n} absent from this workflow.js') }` }
56
+ 'isHardRule', 'longest', 'mergeFindings', 'dedup', 'shouldVerify', 'isProveAttempt', 'countProveAttempt'].map(n => {
57
+ // countProveAttempt is called directly by the checks, so its stub returns NaN and the
58
+ // checks FAIL with a diff instead of the run crashing on an older workflow.js.
59
+ try { return lift(n) } catch {
60
+ return n === 'countProveAttempt'
61
+ ? 'function countProveAttempt() { return NaN }'
62
+ : `function ${n}() { throw new Error('${n} absent from this workflow.js') }`
63
+ }
58
64
  }),
59
65
  ].join('\n')
60
66
 
61
- const { dedup, isHardRule, shouldVerify, sameIssue } =
62
- new Function(preamble + '\nreturn { dedup, isHardRule, shouldVerify, sameIssue }')()
67
+ const { dedup, isHardRule, shouldVerify, sameIssue, isProveAttempt, countProveAttempt } =
68
+ new Function(preamble + '\nreturn { dedup, isHardRule, shouldVerify, sameIssue, isProveAttempt, countProveAttempt }')()
63
69
 
64
70
  let failed = 0
65
71
  function check(name, actual, expected) {
@@ -676,5 +682,20 @@ console.log('\nprove: skipped without an installed test runner')
676
682
  rmSync(tmp, { recursive: true, force: true })
677
683
  }
678
684
 
685
+ console.log('\nprove ledger: a declined prover is a skip, not an attempt')
686
+ // Observed: 6 critical findings, every prover answered attempted:false (no node_modules),
687
+ // and the ledger recorded proven 0/6 as if six tests had run and not failed.
688
+ check('not_attempted is not an attempt', isProveAttempt({ attempted: false, proven: false, outcome: 'not_attempted' }), false)
689
+ check('inconclusive run is an attempt', isProveAttempt({ attempted: true, proven: false, outcome: 'inconclusive' }), true)
690
+ check('proven run is an attempt', isProveAttempt({ attempted: true, proven: true, outcome: 'proven' }), true)
691
+ // The counter path itself, not just the predicate: a declined prover must leave the count unchanged.
692
+ check('ledger: null proof (prover failed or rejected) adds nothing', countProveAttempt(0, null), 0)
693
+ check('ledger: declined prover adds nothing', countProveAttempt(2, { attempted: false, proven: false, outcome: 'not_attempted' }), 2)
694
+ check('ledger: inconclusive prover adds one', countProveAttempt(2, { attempted: true, proven: false, outcome: 'inconclusive' }), 3)
695
+ check('ledger: proven prover adds one', countProveAttempt(2, { attempted: true, proven: true, outcome: 'proven' }), 3)
696
+ // Source guard: a bare increment would bypass the predicate, and no unit check above would notice.
697
+ const bareWrites = src.split('\n').filter(l => /proveAttemptCount\s*(\+\+|\+=|=[^=])/.test(l) && !/countProveAttempt\(|let proveAttemptCount/.test(l))
698
+ check('the attempt count is written only through countProveAttempt', bareWrites, [])
699
+
679
700
  console.log(failed === 0 ? '\nall checks passed\n' : `\n${failed} check(s) FAILED\n`)
680
701
  process.exit(failed === 0 ? 0 : 1)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olegkoval/agent-skills",
3
- "version": "1.62.0",
3
+ "version": "1.62.1",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-apple-kit",
3
3
  "description": "Build and ship Apple platform apps: macOS menubar apps, App Store submissions.",
4
- "version": "1.62.0",
4
+ "version": "1.62.1",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-creative",
3
3
  "description": "Creative and personal projects: photo galleries, music players, listings, wiki editing.",
4
- "version": "1.62.0",
4
+ "version": "1.62.1",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-garmin-kit",
3
3
  "description": "Build, test and publish Garmin Connect IQ watch faces.",
4
- "version": "1.62.0",
4
+ "version": "1.62.1",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-git-tools",
3
3
  "description": "Everyday git and GitHub CLI operations: conventional commits, branch hygiene.",
4
- "version": "1.62.0",
4
+ "version": "1.62.1",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-github-pr",
3
3
  "description": "Drive GitHub pull requests to merge-ready: review-bot loops, CI fixes, descriptions, dependency triage.",
4
- "version": "1.62.0",
4
+ "version": "1.62.1",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -53,13 +53,19 @@ const preamble = [
53
53
  // hardRuleCorroborated is likewise gone from the current file and kept in this
54
54
  // list for the same reason: an older workflow.js calls it from isHardRule.
55
55
  ...['titleTokens', 'sameIssue', 'nearbyLines', 'spanWithinWindow', 'hardRuleCorroborated',
56
- 'isHardRule', 'longest', 'mergeFindings', 'dedup', 'shouldVerify'].map(n => {
57
- try { return lift(n) } catch { return `function ${n}() { throw new Error('${n} absent from this workflow.js') }` }
56
+ 'isHardRule', 'longest', 'mergeFindings', 'dedup', 'shouldVerify', 'isProveAttempt', 'countProveAttempt'].map(n => {
57
+ // countProveAttempt is called directly by the checks, so its stub returns NaN and the
58
+ // checks FAIL with a diff instead of the run crashing on an older workflow.js.
59
+ try { return lift(n) } catch {
60
+ return n === 'countProveAttempt'
61
+ ? 'function countProveAttempt() { return NaN }'
62
+ : `function ${n}() { throw new Error('${n} absent from this workflow.js') }`
63
+ }
58
64
  }),
59
65
  ].join('\n')
60
66
 
61
- const { dedup, isHardRule, shouldVerify, sameIssue } =
62
- new Function(preamble + '\nreturn { dedup, isHardRule, shouldVerify, sameIssue }')()
67
+ const { dedup, isHardRule, shouldVerify, sameIssue, isProveAttempt, countProveAttempt } =
68
+ new Function(preamble + '\nreturn { dedup, isHardRule, shouldVerify, sameIssue, isProveAttempt, countProveAttempt }')()
63
69
 
64
70
  let failed = 0
65
71
  function check(name, actual, expected) {
@@ -676,5 +682,20 @@ console.log('\nprove: skipped without an installed test runner')
676
682
  rmSync(tmp, { recursive: true, force: true })
677
683
  }
678
684
 
685
+ console.log('\nprove ledger: a declined prover is a skip, not an attempt')
686
+ // Observed: 6 critical findings, every prover answered attempted:false (no node_modules),
687
+ // and the ledger recorded proven 0/6 as if six tests had run and not failed.
688
+ check('not_attempted is not an attempt', isProveAttempt({ attempted: false, proven: false, outcome: 'not_attempted' }), false)
689
+ check('inconclusive run is an attempt', isProveAttempt({ attempted: true, proven: false, outcome: 'inconclusive' }), true)
690
+ check('proven run is an attempt', isProveAttempt({ attempted: true, proven: true, outcome: 'proven' }), true)
691
+ // The counter path itself, not just the predicate: a declined prover must leave the count unchanged.
692
+ check('ledger: null proof (prover failed or rejected) adds nothing', countProveAttempt(0, null), 0)
693
+ check('ledger: declined prover adds nothing', countProveAttempt(2, { attempted: false, proven: false, outcome: 'not_attempted' }), 2)
694
+ check('ledger: inconclusive prover adds one', countProveAttempt(2, { attempted: true, proven: false, outcome: 'inconclusive' }), 3)
695
+ check('ledger: proven prover adds one', countProveAttempt(2, { attempted: true, proven: true, outcome: 'proven' }), 3)
696
+ // Source guard: a bare increment would bypass the predicate, and no unit check above would notice.
697
+ const bareWrites = src.split('\n').filter(l => /proveAttemptCount\s*(\+\+|\+=|=[^=])/.test(l) && !/countProveAttempt\(|let proveAttemptCount/.test(l))
698
+ check('the attempt count is written only through countProveAttempt', bareWrites, [])
699
+
679
700
  console.log(failed === 0 ? '\nall checks passed\n' : `\n${failed} check(s) FAILED\n`)
680
701
  process.exit(failed === 0 ? 0 : 1)
@@ -393,6 +393,19 @@ function normalizeProof(result) {
393
393
  }
394
394
  }
395
395
 
396
+ // A prover that declines at its testability gate (no runner, not importable)
397
+ // returns outcome 'not_attempted'. That is a skip, not a failed attempt, so it
398
+ // must not inflate the proven/attempts ratio in the run ledger.
399
+ function isProveAttempt(proof) {
400
+ return proof.attempted === true
401
+ }
402
+
403
+ // The only writer of the run ledger's attempt count. A null proof means the
404
+ // prover agent failed or was rejected, so there is no evidence a test ran.
405
+ function countProveAttempt(count, proof) {
406
+ return Boolean(proof) && isProveAttempt(proof) ? count + 1 : count
407
+ }
408
+
396
409
  // Run thunks in sequential batches, giving the per-finding stages a ceiling.
397
410
  //
398
411
  // The review stage is bounded by its dimension count, but verify, critic and
@@ -951,7 +964,6 @@ const budgetAtStart = budget.spent()
951
964
  await batched(capped.map(function(finding) {
952
965
  return async function() {
953
966
  agentCount++
954
- proveAttemptCount++
955
967
  const result = await agent(proverPrompt(finding), {
956
968
  label: 'prove:' + finding.file + ':' + finding.line,
957
969
  phase: 'Prove',
@@ -968,6 +980,7 @@ const budgetAtStart = budget.spent()
968
980
 
969
981
  const proof = normalizeProof(result)
970
982
  finding.proof = proof
983
+ proveAttemptCount = countProveAttempt(proveAttemptCount, proof)
971
984
  if (proof.proven === true) {
972
985
  provenCount++
973
986
  finding.verificationStatus = 'proven'
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-obsidian",
3
3
  "description": "Keep an Obsidian vault in sync with work: PR sync, task rollover, morning routine.",
4
- "version": "1.62.0",
4
+ "version": "1.62.1",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-product",
3
3
  "description": "Take a product idea to a shippable build: MVP passes, full-stack scaffolds, UX/UI quality loops, launch plans.",
4
- "version": "1.62.0",
4
+ "version": "1.62.1",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-reflection",
3
3
  "description": "Look back and improve: self-critique, retrospectives, performance review, rapid learning.",
4
- "version": "1.62.0",
4
+ "version": "1.62.1",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-release",
3
3
  "description": "Ship a release: semantic-release setup, changelogs, store listing copy, release-day routine.",
4
- "version": "1.62.0",
4
+ "version": "1.62.1",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-skill-meta",
3
3
  "description": "Author and maintain agent skills and the AI toolchain itself.",
4
- "version": "1.62.0",
4
+ "version": "1.62.1",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-web-ops",
3
3
  "description": "Operate a website: WAF rules, search console audits, analytics bootstrap, docs indexes.",
4
- "version": "1.62.0",
4
+ "version": "1.62.1",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },