pwn 0.5.779 → 0.5.781

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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -3
  3. data/documentation/AI-Integration.md +4 -4
  4. data/documentation/AWS.md +10 -9
  5. data/documentation/Agent-Tool-Registry.md +20 -17
  6. data/documentation/Blockchain.md +3 -2
  7. data/documentation/Bounty.md +8 -6
  8. data/documentation/BurpSuite.md +6 -10
  9. data/documentation/CLI-Drivers.md +7 -4
  10. data/documentation/Capability-Broker-Sandbox.md +1 -1
  11. data/documentation/Configuration.md +23 -15
  12. data/documentation/Contributing.md +3 -3
  13. data/documentation/Cron.md +3 -2
  14. data/documentation/Diagrams.md +9 -3
  15. data/documentation/Drivers.md +12 -6
  16. data/documentation/Extrospection.md +25 -5
  17. data/documentation/FFI.md +15 -25
  18. data/documentation/Fuzzing.md +13 -13
  19. data/documentation/General-PWN-Usage.md +7 -4
  20. data/documentation/Harness-Evaluation.md +90 -3
  21. data/documentation/Home.md +6 -5
  22. data/documentation/How-PWN-Works.md +9 -10
  23. data/documentation/Installation.md +12 -11
  24. data/documentation/Metasploit.md +13 -19
  25. data/documentation/Mistakes.md +2 -2
  26. data/documentation/NmapIt.md +6 -3
  27. data/documentation/Operability.md +99 -0
  28. data/documentation/Persistence.md +3 -2
  29. data/documentation/Plugin-Degradation.md +4 -2
  30. data/documentation/Plugins.md +4 -11
  31. data/documentation/Policy-Benchmark.md +4 -0
  32. data/documentation/Reinforcement-Learning.md +19 -3
  33. data/documentation/Reporting.md +6 -5
  34. data/documentation/SAST.md +15 -10
  35. data/documentation/SDR-Decoder-Coverage.md +10 -4
  36. data/documentation/SDR.md +28 -40
  37. data/documentation/Session-Workflow.md +25 -12
  38. data/documentation/Sessions.md +7 -0
  39. data/documentation/Skills-Memory-Learning.md +11 -4
  40. data/documentation/Swarm.md +6 -0
  41. data/documentation/Transparent-Browser.md +1 -1
  42. data/documentation/Troubleshooting.md +6 -3
  43. data/documentation/What-is-PWN.md +4 -4
  44. data/documentation/Why-PWN.md +1 -1
  45. data/documentation/diagrams/agent-tool-registry.svg +219 -180
  46. data/documentation/diagrams/ai-integration-tool-calling.svg +35 -34
  47. data/documentation/diagrams/code-scanning-sast.svg +78 -78
  48. data/documentation/diagrams/cron-scheduling.svg +165 -145
  49. data/documentation/diagrams/dot/_THEME.md +6 -4
  50. data/documentation/diagrams/dot/agent-tool-registry.dot +6 -2
  51. data/documentation/diagrams/dot/ai-integration-tool-calling.dot +1 -1
  52. data/documentation/diagrams/dot/code-scanning-sast.dot +8 -8
  53. data/documentation/diagrams/dot/cron-scheduling.dot +2 -0
  54. data/documentation/diagrams/dot/driver-framework.dot +1 -1
  55. data/documentation/diagrams/dot/extrospection-world-awareness.dot +2 -2
  56. data/documentation/diagrams/dot/fuzzing-workflow.dot +3 -3
  57. data/documentation/diagrams/dot/history-to-drivers.dot +1 -1
  58. data/documentation/diagrams/dot/memory-skills-detailed.dot +3 -3
  59. data/documentation/diagrams/dot/mistakes-negative-feedback.dot +2 -2
  60. data/documentation/diagrams/dot/overall-pwn-architecture.dot +33 -121
  61. data/documentation/diagrams/dot/persistence-filesystem.dot +2 -2
  62. data/documentation/diagrams/dot/plugin-ecosystem.dot +2 -2
  63. data/documentation/diagrams/dot/pwn-ai-feedback-learning-loop.dot +31 -167
  64. data/documentation/diagrams/dot/pwn-repl-prototyping.dot +1 -1
  65. data/documentation/diagrams/dot/reinforcement-learning.dot +15 -7
  66. data/documentation/diagrams/dot/reporting-pipeline.dot +5 -3
  67. data/documentation/diagrams/dot/reverse-engineering-flow.dot +3 -3
  68. data/documentation/diagrams/dot/sdr-radio-flow.dot +5 -5
  69. data/documentation/diagrams/dot/sessions-cron-automation.dot +1 -1
  70. data/documentation/diagrams/dot/swarm-multi-agent.dot +3 -3
  71. data/documentation/diagrams/dot/task-summarizer.dot +2 -2
  72. data/documentation/diagrams/dot/web-application-testing.dot +4 -3
  73. data/documentation/diagrams/dot/zero-day-research-flow.dot +4 -3
  74. data/documentation/diagrams/driver-framework.svg +1 -1
  75. data/documentation/diagrams/extrospection-world-awareness.svg +178 -178
  76. data/documentation/diagrams/fuzzing-workflow.svg +58 -58
  77. data/documentation/diagrams/history-to-drivers.svg +42 -42
  78. data/documentation/diagrams/memory-skills-detailed.svg +210 -210
  79. data/documentation/diagrams/mistakes-negative-feedback.svg +116 -116
  80. data/documentation/diagrams/overall-pwn-architecture.svg +248 -404
  81. data/documentation/diagrams/persistence-filesystem.svg +143 -143
  82. data/documentation/diagrams/plugin-ecosystem.svg +100 -100
  83. data/documentation/diagrams/pwn-ai-feedback-learning-loop.svg +233 -752
  84. data/documentation/diagrams/pwn-repl-prototyping.svg +27 -27
  85. data/documentation/diagrams/reinforcement-learning.svg +295 -221
  86. data/documentation/diagrams/reporting-pipeline.svg +94 -80
  87. data/documentation/diagrams/reverse-engineering-flow.svg +31 -31
  88. data/documentation/diagrams/sdr-radio-flow.svg +157 -155
  89. data/documentation/diagrams/sessions-cron-automation.svg +13 -13
  90. data/documentation/diagrams/swarm-multi-agent.svg +86 -86
  91. data/documentation/diagrams/task-summarizer.svg +57 -57
  92. data/documentation/diagrams/web-application-testing.svg +81 -75
  93. data/documentation/diagrams/zero-day-research-flow.svg +101 -92
  94. data/documentation/pwn-REPL.md +5 -3
  95. data/documentation/pwn-ai-Agent.md +18 -14
  96. data/documentation/pwn_silent_help_learn_demo.gif +0 -0
  97. data/etc/default_skills/pwn/ai/agent/learning/SKILL.md +1 -0
  98. data/lib/pwn/ai/agent/learning.rb +46 -1
  99. data/lib/pwn/ai/agent/loop.rb +6 -3
  100. data/lib/pwn/ai/agent/policy_evaluation.rb +5 -1
  101. data/lib/pwn/ai/agent/reward.rb +9 -0
  102. data/lib/pwn/version.rb +1 -1
  103. data/spec/fixtures/harness/completion_regressions.json +10 -0
  104. data/spec/fixtures/harness/completion_regressions.json.sha256 +1 -0
  105. data/spec/integration/harness_evaluation_spec.rb +13 -0
  106. data/spec/lib/pwn/ai/agent/learning_spec.rb +22 -0
  107. data/spec/lib/pwn/ai/agent/loop_spec.rb +39 -0
  108. data/spec/lib/pwn/ai/agent/policy_evaluation_spec.rb +6 -1
  109. data/spec/lib/pwn/ai/agent/reward_spec.rb +21 -0
  110. data/spec/support/harness/evaluate.rb +1 -1
  111. data/third_party/pwn_rdoc.jsonl +2 -1
  112. metadata +10 -7
@@ -2195,7 +2195,8 @@ module PWN
2195
2195
  pairs.each do |pair|
2196
2196
  tool = pair.find { |m| m[:role].to_s == 'tool' }
2197
2197
  prev = collapsed.last&.find { |m| m[:role].to_s == 'tool' }
2198
- next if tool && prev && tool[:content].to_s.strip == prev[:content].to_s.strip
2198
+ # Compare raw bytes: existing history may contain malformed tool output.
2199
+ next if tool && prev && tool[:content].to_s.b.strip == prev[:content].to_s.b.strip
2199
2200
 
2200
2201
  collapsed << pair
2201
2202
  end
@@ -2241,8 +2242,10 @@ module PWN
2241
2242
  FileUtils.mkdir_p(dir)
2242
2243
  path = File.join(dir, "#{digest[0, 12]}.txt")
2243
2244
  File.binwrite(path, text) unless File.file?(path)
2244
- head = text.byteslice(0, 2_048).to_s
2245
- tail = text.bytesize > 3_072 ? text.byteslice(-1_024, 1_024).to_s : ''
2245
+ # Keep the artifact/digest byte-exact; only the displayed excerpt is text.
2246
+ # Byte slicing can bisect a multibyte character at either boundary.
2247
+ head = text.byteslice(0, 2_048).to_s.dup.force_encoding(Encoding::UTF_8).scrub
2248
+ tail = text.bytesize > 3_072 ? text.byteslice(-1_024, 1_024).to_s.dup.force_encoding(Encoding::UTF_8).scrub : ''
2246
2249
  mid = tail.empty? ? '' : "\n...\n#{tail}"
2247
2250
  "#{head}#{mid}\n[compacted path=#{path} sha256=#{digest} bytes=#{text.bytesize} ref=#{path}]"
2248
2251
  rescue StandardError
@@ -87,7 +87,9 @@ module PWN
87
87
  File.open(backup, File::WRONLY | File::CREAT | File::EXCL, 0o600) { |file| file.write(baseline) }
88
88
  end
89
89
  replace(path: live, bytes: candidate)
90
- { promoted: true, live_path: live, rollback_path: backup, baseline_sha256: prior_digest,
90
+ { promoted: true, receipt_version: 1, change_kind: 'routing_policy',
91
+ acceptance_sha256: Digest::SHA256.hexdigest(JSON.generate(deterministic(value: replayed))),
92
+ live_path: live, rollback_path: backup, baseline_sha256: prior_digest,
91
93
  candidate_sha256: candidate_digest, replayed_seeds: replayed.map { |r| r[:seed] } }
92
94
  rescue StandardError => e
93
95
  { promoted: false, reason: e.message }
@@ -98,6 +100,8 @@ module PWN
98
100
  raise ArgumentError, 'stop all policy writers and set quiescent: true' unless opts[:quiescent] == true
99
101
 
100
102
  receipt = opts.fetch(:receipt)
103
+ raise ArgumentError, 'successful versioned policy promotion receipt required' unless receipt[:promoted] == true && receipt[:receipt_version] == 1 && receipt[:change_kind] == 'routing_policy' && receipt[:acceptance_sha256].to_s.match?(/\A[0-9a-f]{64}\z/)
104
+
101
105
  live = File.expand_path(opts.fetch(:live_path))
102
106
  prior_digest = receipt.fetch(:baseline_sha256)
103
107
  raise ArgumentError, 'invalid rollback digest' unless prior_digest.is_a?(String) && prior_digest.match?(/\A[0-9a-f]{64}\z/)
@@ -180,6 +180,9 @@ module PWN
180
180
  v[:confidence] = [v[:confidence].to_f, ground[:confidence].to_f].max if ground[:confidence]
181
181
  end
182
182
 
183
+ # Preserve the evaluator's original completion claim before verification
184
+ # can lower its verdict. This is diagnostic, never acceptance evidence.
185
+ v[:claimed_completion] = v[:verdict].to_s == 'solved'
183
186
  v[:judge_score] = v[:score].to_f
184
187
  v[:score_quality] = v[:score].to_f
185
188
  v[:verification] = if opts[:verification].is_a?(Hash)
@@ -272,6 +275,12 @@ module PWN
272
275
  :pass
273
276
  end
274
277
  end
278
+ v[:verified_completion] = vv.nil? ? nil : vv == :pass
279
+ v[:false_completion] = if v[:claimed_completion] == true
280
+ vv.nil? ? nil : vv == :fail
281
+ elsif v[:claimed_completion] == false
282
+ false
283
+ end
275
284
  v[:verifier_verdict] = vv
276
285
  v[:confidence] = 1.0 if vv
277
286
  if vv == :fail || v.dig(:grounded, :verdict).to_s == 'refuted'
data/lib/pwn/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PWN
4
- VERSION = '0.5.779'
4
+ VERSION = '0.5.781'
5
5
  end
@@ -0,0 +1,10 @@
1
+ {
2
+ "schema": "pwn-completion-regressions-v1",
3
+ "split": "regression",
4
+ "provenance": "Source-reproduced HarnessEvaluation.grade false-success accounting defects: vacuous empty checks, nonzero process exit despite correct bytes, and resource cap despite correct bytes. These are public regression stimuli, not held-out learning evidence.",
5
+ "cases": [
6
+ {"id": "empty-acceptance-claim", "checks": [], "result": {"stdout": "DONE", "exit_status": 0, "resource_cap": false}, "outcome": "FAIL"},
7
+ {"id": "failed-process-claim", "checks": [{"path": "result.txt", "bytes": "correct"}], "result": {"stdout": "DONE", "exit_status": 1, "resource_cap": false}, "outcome": "FAIL"},
8
+ {"id": "capped-process-claim", "checks": [{"path": "result.txt", "bytes": "correct"}], "result": {"stdout": "DONE", "exit_status": 0, "resource_cap": true}, "outcome": "INCOMPLETE"}
9
+ ]
10
+ }
@@ -0,0 +1 @@
1
+ 9368d0704929f9ed4ab448f8bfb0958d19de89cb09a934d20d2cb0a36a22ee7b
@@ -23,6 +23,19 @@ RSpec.describe 'offline harness evaluation' do
23
23
  expect { HarnessEvaluation.validate_parity!(pinned, pinned.merge('provider' => 'different')) }.to raise_error(ArgumentError)
24
24
  end
25
25
 
26
+ it 'counts claims without checks, nonzero exits, and capped claims as false completion' do
27
+ Dir.mktmpdir do |root|
28
+ corpus = HarnessExperiments.locked_json(File.join(HarnessEvaluation::ROOT, 'spec/fixtures/harness/completion_regressions.json'))
29
+ expect(corpus.fetch('split')).to eq('regression')
30
+ File.write(File.join(root, 'result.txt'), 'correct')
31
+ corpus.fetch('cases').each do |failure|
32
+ task = { 'checks' => failure.fetch('checks'), 'success_marker' => 'DONE' }
33
+ result = failure.fetch('result').transform_keys(&:to_sym)
34
+ expect(HarnessEvaluation.grade(task, root, result)).to include(outcome: failure.fetch('outcome'), false_success: true), failure.fetch('id')
35
+ end
36
+ end
37
+ end
38
+
26
39
  it 'grades independent bytes and counts observed repeated identities, not tool attempts' do
27
40
  Dir.mktmpdir do |root|
28
41
  File.write(File.join(root, 'result.txt'), 'wrong')
@@ -5,6 +5,28 @@ require 'tmpdir'
5
5
  require 'fileutils'
6
6
 
7
7
  describe PWN::AI::Agent::Learning do
8
+ describe 'failure regression tasks' do
9
+ include_context 'pwn tmp sandbox'
10
+
11
+ it 'exports a reviewed replay recipe only for a persisted independently verified failure' do
12
+ request = 'Write result.txt'
13
+ checks = [{ requirement: request, kind: :file, path: 'result.txt', expected: 'correct' }]
14
+ verification = PWN::AI::Agent::Verification.run(request: request, requirements: [request], checks: checks, root: @tmp)
15
+ row = described_class.note_outcome(task: request, outcome: { score: 0.9, source: :llm_orm, claimed_completion: true, verification: verification })
16
+ recipe = described_class.regression_task(outcome_id: row[:id], request: request, checks: checks)
17
+ expect(recipe).to include(schema: 'pwn-failure-regression-v1', split: 'regression', source_outcome_id: row[:id])
18
+ expect(recipe[:source_verification_sha256]).to eq(Digest::SHA256.hexdigest(JSON.generate(row[:verification])))
19
+ replay = PWN::AI::Agent::Verification.run(recipe[:contract].merge(root: @tmp))
20
+ expect(replay[:status]).to eq(:fail)
21
+ File.write(File.join(@tmp, 'result.txt'), 'correct')
22
+ expect(PWN::AI::Agent::Verification.run(recipe[:contract].merge(root: @tmp))[:status]).to eq(:pass)
23
+ expect { described_class.regression_task(outcome_id: row[:id], request: 'other', checks: checks) }.to raise_error(ArgumentError, /request/)
24
+ expect { described_class.regression_task(outcome_id: row[:id], request: request, checks: []) }.to raise_error(ArgumentError, /coverage/)
25
+ expect { described_class.regression_task(outcome_id: row[:id], request: request, checks: checks.map { |c| c.merge(path: '../escape') }) }.to raise_error(ArgumentError, /relative/)
26
+ expect { described_class.regression_task(outcome_id: 'missing', request: request, checks: checks) }.to raise_error(ArgumentError, /verified failure/)
27
+ end
28
+ end
29
+
8
30
  describe 'evidence failure safety' do
9
31
  before do
10
32
  home = Dir.mktmpdir
@@ -1304,6 +1304,45 @@ describe PWN::AI::Agent::Loop do # rubocop:disable Metrics/BlockLength
1304
1304
  expect(src).not_to match(/compact_history!\(messages: messages\) if local/)
1305
1305
  end
1306
1306
 
1307
+ it 'keeps UTF-8 previews valid across repeated history compaction' do
1308
+ Dir.mktmpdir('pwn-history-encoding') do |dir|
1309
+ allow(Dir).to receive(:home).and_return(dir)
1310
+ messages = [{ role: 'system', content: 'sys' }, { role: 'user', content: 'goal' }]
1311
+ 8.times do |n|
1312
+ messages << { role: 'assistant', content: '', tool_calls: [{ id: "c#{n}" }] }
1313
+ messages << { role: 'tool', tool_call_id: "c#{n}", content: "a#{'é' * 3000}#{n}" }
1314
+ end
1315
+ 2.times do
1316
+ expect { described_class.send(:compact_history!, messages: messages) }.not_to output(/compact_history swallowed/).to_stderr
1317
+ expect(messages.all? { |msg| msg[:content].valid_encoding? }).to be(true)
1318
+ end
1319
+ end
1320
+ end
1321
+
1322
+ it 'preserves raw spilled bytes while rendering malformed and binary-tagged text safely' do
1323
+ Dir.mktmpdir('pwn-history-binary') do |dir|
1324
+ allow(Dir).to receive(:home).and_return(dir)
1325
+ ["a#{'é' * 3000}".b, "a\xff#{'é' * 3000}"].each do |text|
1326
+ preview = described_class.send(:spill_tool_body, text: text)
1327
+ expect(preview.encoding).to eq(Encoding::UTF_8)
1328
+ expect(preview.valid_encoding?).to be(true)
1329
+ expect(preview).to include('é', '[compacted path=')
1330
+ path = preview[/\[compacted path=(.*?) sha256=/, 1]
1331
+ expect(File.binread(path)).to eq(text.b)
1332
+ end
1333
+ end
1334
+ end
1335
+
1336
+ it 'compacts existing malformed tool history without swallowing encoding errors' do
1337
+ messages = [{ role: 'system', content: 'sys' }, { role: 'user', content: 'goal' }]
1338
+ 8.times do |n|
1339
+ messages << { role: 'assistant', tool_calls: [{ id: "c#{n}" }] }
1340
+ messages << { role: 'tool', tool_call_id: "c#{n}", content: "invalid\xff#{n}" }
1341
+ end
1342
+ expect { described_class.send(:compact_history!, messages: messages) }.not_to output(/compact_history swallowed/).to_stderr
1343
+ expect(messages.count { |msg| msg[:role] == 'tool' }).to eq(6)
1344
+ end
1345
+
1307
1346
  it 'shrinks tool bodies when history is fat' do
1308
1347
  msgs = [
1309
1348
  { role: 'system', content: 'sys' },
@@ -100,7 +100,12 @@ describe 'PWN::AI::Agent::PolicyEvaluation' do
100
100
  File.unlink(live)
101
101
  File.write(live, File.read(baseline))
102
102
  result = evaluator.promote(enabled: true, quiescent: true, baseline: baseline, candidate: candidate, reports: reports, live_path: live)
103
- expect(result).to include(promoted: true)
103
+ expect(result).to include(promoted: true, receipt_version: 1, change_kind: 'routing_policy')
104
+ expect(result[:acceptance_sha256]).to match(/\A[0-9a-f]{64}\z/)
105
+ [result.merge(promoted: false), result.merge(receipt_version: 2), result.except(:receipt_version), result.merge(change_kind: 'skill'), result.merge(acceptance_sha256: 'invalid')].each do |invalid|
106
+ expect(evaluator.rollback(enabled: true, quiescent: true, live_path: live, receipt: invalid)).to include(rolled_back: false, reason: /receipt/)
107
+ expect(File.binread(live)).to eq(File.binread(candidate))
108
+ end
104
109
  expect(File.binread(live)).to eq(File.binread(candidate))
105
110
  expect(File.binread(result[:rollback_path])).to eq(File.binread(baseline))
106
111
  expect(result[:replayed_seeds]).to eq([0, 1])
@@ -4,6 +4,27 @@ require 'spec_helper'
4
4
  require 'tmpdir'
5
5
 
6
6
  describe PWN::AI::Agent::Reward do
7
+ describe 'completion accounting' do
8
+ include_context 'pwn tmp sandbox'
9
+
10
+ it 'preserves a refuted completion claim through resolution and durable learning' do
11
+ request = 'Write answer.txt'
12
+ report = PWN::AI::Agent::Verification.run(request: request, requirements: [request], root: @tmp,
13
+ checks: [{ requirement: request, kind: :file, path: 'answer.txt', expected: 'correct' }])
14
+ result = described_class.resolve_outcome(outcome: { score: 0.95, source: :llm_orm, claimed_completion: true, verification: report })
15
+ expect(result).to include(verified_completion: false, false_completion: true)
16
+ expect(described_class.resolve_outcome(outcome: result)).to eq(result)
17
+ row = PWN::AI::Agent::Learning.note_outcome(task: request, outcome: result)
18
+ expect(row).to include(claimed_completion: true, verified_completion: false, false_completion: true)
19
+ expect(PWN::AI::Agent::Learning.stats).to include(completion_claims: 1, false_completions: 1, verified_completions: 0)
20
+ end
21
+
22
+ it 'keeps unverified claims unknown rather than labeling them false or verified' do
23
+ result = described_class.resolve_outcome(outcome: { score: 0.95, source: :llm_orm, claimed_completion: true })
24
+ expect(result).to include(verified_completion: nil, false_completion: nil)
25
+ end
26
+ end
27
+
7
28
  describe 'labeled transcript calibration' do
8
29
  include_context 'pwn tmp sandbox'
9
30
 
@@ -62,7 +62,7 @@ module HarnessEvaluation
62
62
  passed ? 'PASS' : 'FAIL'
63
63
  end
64
64
  { outcome: outcome, checks: checks, tool_timeouts: timeouts,
65
- false_success: claimed && !checks.all? { |row| row[:passed] },
65
+ false_success: claimed && outcome != 'PASS',
66
66
  repeated_effects: effects.tally.values.sum { |count| count - 1 }, observed_effects: effects }
67
67
  end
68
68
 
@@ -357,6 +357,7 @@
357
357
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.reconcile_verdict_tags! Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.reconcile_verdict_tags!`: "}]}
358
358
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.recover_predicted_from_session Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.recover_predicted_from_session`: "}]}
359
359
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.reflect Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.reflect`: Supported Method Parameters\n\nreport = PWN::AI::Agent::Learning.reflect(\n\nsession_id: 'required - PWN::Sessions id to analyse',\ndry_run: 'optional - when true, do not write to Memory/Skills (default false)'\n\n)\n\nUses PWN::AI::Agent::Reflect (when available) to LLM-summarise the session into structured lessons. Falls back to a heuristic extractor when module_reflection is disabled so learning never stops.\n"}]}
360
+ {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.regression_task Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.regression_task`: "}]}
360
361
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.requeue_conflicted Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.requeue_conflicted`: "}]}
361
362
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.reset Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.reset`: Supported Method Parameters\n\nPWN::AI::Agent::Learning.reset\n"}]}
362
363
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.rl_skill_notes Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.rl_skill_notes`: "}]}
@@ -368,7 +369,7 @@
368
369
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.should_gc_stores? Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.should_gc_stores?`: "}]}
369
370
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.skill_body_without_frontmatter Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.skill_body_without_frontmatter`: "}]}
370
371
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.skills_dir Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.skills_dir`: "}]}
371
- {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.stats Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.stats`: Supported Method Parameters\n\nstats = PWN::AI::Agent::Learning.stats\n"}]}
372
+ {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.stats Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.stats`: "}]}
372
373
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.to_context Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.to_context`: Supported Method Parameters\n\nctx = PWN::AI::Agent::Learning.to_context(\n\nlimit: 'optional - number of recent outcomes to surface (default 5)'\n\n)\n"}]}
373
374
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.transcript_text Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.transcript_text`: "}]}
374
375
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.update_skill Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.update_skill`: "}]}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pwn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.779
4
+ version: 0.5.781
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.
@@ -505,28 +505,28 @@ dependencies:
505
505
  requirements:
506
506
  - - '='
507
507
  - !ruby/object:Gem::Version
508
- version: 1.8.0
508
+ version: 1.8.1
509
509
  type: :runtime
510
510
  prerelease: false
511
511
  version_requirements: !ruby/object:Gem::Requirement
512
512
  requirements:
513
513
  - - '='
514
514
  - !ruby/object:Gem::Version
515
- version: 1.8.0
515
+ version: 1.8.1
516
516
  - !ruby/object:Gem::Dependency
517
517
  name: meshtastic
518
518
  requirement: !ruby/object:Gem::Requirement
519
519
  requirements:
520
520
  - - '='
521
521
  - !ruby/object:Gem::Version
522
- version: 0.0.188
522
+ version: 0.0.189
523
523
  type: :development
524
524
  prerelease: false
525
525
  version_requirements: !ruby/object:Gem::Requirement
526
526
  requirements:
527
527
  - - '='
528
528
  - !ruby/object:Gem::Version
529
- version: 0.0.188
529
+ version: 0.0.189
530
530
  - !ruby/object:Gem::Dependency
531
531
  name: metasm
532
532
  requirement: !ruby/object:Gem::Requirement
@@ -953,14 +953,14 @@ dependencies:
953
953
  requirements:
954
954
  - - '='
955
955
  - !ruby/object:Gem::Version
956
- version: 1.92.0
956
+ version: 1.92.1
957
957
  type: :runtime
958
958
  prerelease: false
959
959
  version_requirements: !ruby/object:Gem::Requirement
960
960
  requirements:
961
961
  - - '='
962
962
  - !ruby/object:Gem::Version
963
- version: 1.92.0
963
+ version: 1.92.1
964
964
  - !ruby/object:Gem::Dependency
965
965
  name: rubocop-rake
966
966
  requirement: !ruby/object:Gem::Requirement
@@ -1447,6 +1447,7 @@ files:
1447
1447
  - documentation/Metasploit.md
1448
1448
  - documentation/Mistakes.md
1449
1449
  - documentation/NmapIt.md
1450
+ - documentation/Operability.md
1450
1451
  - documentation/PWN.png
1451
1452
  - documentation/Persistence.md
1452
1453
  - documentation/Plugin-Degradation.md
@@ -6579,6 +6580,8 @@ files:
6579
6580
  - spec/documentation/prompt_version_placeholder_spec.rb
6580
6581
  - spec/fixtures/harness/adapters.json
6581
6582
  - spec/fixtures/harness/adapters.json.sha256
6583
+ - spec/fixtures/harness/completion_regressions.json
6584
+ - spec/fixtures/harness/completion_regressions.json.sha256
6582
6585
  - spec/fixtures/harness/experiment_gold.json
6583
6586
  - spec/fixtures/harness/experiment_gold.json.sha256
6584
6587
  - spec/fixtures/harness/experiment_tasks.json