os-me: the predictor returns YAML; PredictionParser reads YAML and the old line format #1292

Closed
opened 2026-10-23 21:44:57 +00:00 by jared · 2 comments
Owner

Problem

The predict-mode answer format is prose in ~/dev/os-me-store/ENTRY.md section 5: a PREDICTION header, then Action:, Toward:, He would type:, a Why: list, and Confidence: lines. Step 1 item 5 of plugins/os-me/skills/predict/SKILL.md adds Source:, Cost:, Band:, and Evidence: lines. Code reads this text with regexes in plugins/os-me/lib/os_me/prediction_parser.rb (RULING, CONFIDENCE, WHY, TRIGGER, LEVER_LINES). A small change in format, such as bold markup, a moved line, or a percent sign that is not there, gives a wrong or empty row and no error.

Jared ruled on 2026-10-23 that agent output that code reads must be machine-readable. Thus the predictor must return YAML. Old transcripts keep the line format and stay read-only, and the Stop-hook recorder and the extractor still read them. Thus the parser must read both formats. Past data is not converted: the Store prediction-log.jsonl is already JSON.

Readers of the format (grep for PredictionParser, prediction_candidates, Confidence:, PREDICTION, Toward):

  • plugins/os-me/lib/os_me/prediction_parser.rb: the only parser (last_prediction, prediction?, parse, and toward from the blocking ticket).
  • plugins/os-me/hooks/cli_appender.rb (prediction_shown?, the Stop-hook ready check) calls last_prediction.
  • plugins/os-me/hooks/record_prediction.rb and plugins/os-me/hooks/prediction_recorder.rb: the Stop hook. It calls CliAppender, which runs OsMe::CLI append.
  • plugins/os-me/lib/os_me/cli/append_request.rb (append) calls last_prediction and parse, then writes the rows through PredictionLog.
  • plugins/os-me/lib/os_me/transcript_reader.rb (prediction_candidates) supplies the texts. It does not parse the format.
  • plugins/os-me/lib/os_me/prediction_log.rb reads and writes JSONL rows only. It does not read the transcript format. No change.
  • plugins/os-me/lib/os_me/confidence_extractor.rb, called from moment_extractor.rb (stated_percent), reads a free-text percent from any AI message. A YAML confidence: 80 has no %, so without a change every new prediction message gives stated_percent nil. S10 calibration needs that number, so this ticket makes ConfidenceExtractor take the confidence from a YAML prediction block first.
  • Score run: plugins/os-me/lib/os_me/predictor.rb and scorer.rb give the prediction text to judge.rb, which sends it verbatim to a model through eval/judge-prompt.md. No regex. No change.

Approach

Decisions:

  1. YAML shape. The predictor returns one fenced block with the info string yaml. Its only top key is prediction::

    ```yaml
    prediction:
      action: correct
      toward: "Keep StepOutcome in Gate; reject the move to Runner."
      he_would_type: "No, keep it in Gate. Runner must not know step results."
      why:
        - "T2: he rejects moves that widen Runner"
        - "framing 6"
      confidence: 80
      source: precedent
      cost: low
      band: 80
      evidence:
        before: 55
        after: 82
        moved_by: "ruling R12 in rulings.md"
    ```
    

    action is one of accept, correct, or redirect. why is a list of one to three quoted strings. confidence is an integer from 0 to 100, with no %. source, cost, band, and evidence are present only when the brief has row labels or the target-confidence step ran. One block holds one ruling, with the id session:1. Lettered multi-ruling predictions stay readable only in the old format.

  2. Display. Skill step 3 shows the agent's result as is under the heading "Prediction": the YAML block, not changed. The blind reminder line from step 2 goes after the closing fence. Thus the transcript holds the YAML block, and the recorder parses it there. No markdown rendering.

  3. Format detection. A text uses the YAML format when it has a line that is exactly ```yaml (or ```yml) and the next line starts with prediction:. The block body runs to the next ``` line, or to the end of the text. If a text has more than one such block, the last block is used. All other text goes to the existing line path, which does not change. prediction? uses only this detection and the existing CONFIDENCE line, so it never raises.

  4. Malformed block. When a detected block does not load with YAML.safe_load, when prediction: is not a mapping, or when confidence is not an integer from 0 to 100, parse and toward raise OsMe::PredictionParser::MalformedPrediction (an OsMe::Error). The message names the fault. The error surfaces in OsMe::CLI.dispatch, which changes it to a Thor::Error. append then exits 1 and writes the message to stderr. In the Stop hook this is a hook error that the session shows. mark_recorded does not run, so no row is written and the pending invocation stays unrecorded.

Orchestrator work: in the same change, the orchestrator makes these text edits, because the pipeline tests cover only the parser. (a) In ~/dev/os-me-store/ENTRY.md section 5 (the Store repo, not cc-os), replace the PREDICTION line block with the YAML block of decision 1, inside a four-backtick outer fence. State "return exactly this fenced yaml block, nothing before it; quote every string that holds a colon". (b) In ~/dev/os-me-store/brief.md line 18, replace "under a "## Prediction" heading, with the action, reasons, and a confidence number" with "as the fenced yaml block of ENTRY.md section 5". (c) In plugins/os-me/skills/predict/SKILL.md: in step 1, change the Evidence: <before>% -> <after>% line instruction to the evidence: mapping, and change item 5 to "Add the keys source, cost, band, and evidence to the prediction: mapping". In step 2, exit 1, put the printed line after the closing fence. In step 3, show the result as is under the heading "Prediction". Then run bin/refresh-plugins, and commit the Store edit in ~/dev/os-me-store.

Required work:

  1. PredictionParser detects the fenced prediction: YAML block, and OsMe::PredictionParser::YamlPrediction loads it with YAML.safe_load. check: present YAML.safe_load in plugins/os-me/lib/os_me/prediction_parser/yaml_prediction.rb
  2. Add OsMe::PredictionParser::MalformedPrediction < OsMe::Error in its own file, like prediction_log/unknown_id.rb. check: present class MalformedPrediction < OsMe::Error in plugins/os-me/lib/os_me/prediction_parser/malformed_prediction.rb
  3. PredictionParser#toward returns the toward key of a YAML block through YamlPrediction#toward and keeps the line path for old text. check: present def toward in plugins/os-me/lib/os_me/prediction_parser/yaml_prediction.rb
  4. ConfidenceExtractor returns the confidence of a YAML prediction block when the text has one, else its existing percent path. A malformed block raises MalformedPrediction. check: present PredictionParser in plugins/os-me/lib/os_me/confidence_extractor.rb

Acceptance criteria

  1. Given a text that has the YAML block of decision 1 with action: correct, toward: "Keep it in Gate.", and confidence: 80, and no lever keys, when PredictionParser#parse reads it, then it returns one row with id: 'session:1', text: 'correct: Keep it in Gate.', and confidence: 80, and the row has no lever keys.
  2. Given a YAML block whose why list is ["T2: widens Runner", "framing 6", "A5 and T2 apply"], when parse reads it, then triggers is ["T2", "A5"].
  3. Given a YAML block with source: precedent, cost: medium, band: 80, and evidence: {before: 55, after: 82, moved_by: "R12"}, when parse reads it, then the row has source: 'precedent', cost: 'medium', band: 80, evidence_before: 55, and evidence_after: 82.
  4. Given the old ENTRY.md section 5 text (PREDICTION, Action: accept, Toward: ..., He would type: ..., Why: with a - T2 ... bullet, Confidence: 70%), when parse reads it, then it returns one row with id session:1 and confidence 70, as before this change. The existing prediction_parser_test.rb, lever_fields_test.rb, and prediction_fields_test.rb cases pass unchanged.
  5. Given texts ["no prediction here", <YAML block text with no "Confidence:" line>, "Done."], when last_prediction reads them, then it returns the YAML block text, and prediction? is true for that text.
  6. Given a text with a ```yaml block whose first key is plan:, when prediction? reads it, then it returns false.
  7. Given a YAML block that does not load (for example why: [unclosed), when parse reads it, then it raises OsMe::PredictionParser::MalformedPrediction, and prediction? on the same text returns true and does not raise. When OsMe::CLI append reads a transcript whose last assistant message is that text, it exits 1 with the message on stderr, and the log has no row.
  8. Given a YAML block with confidence: "80%", or confidence: 150, or no confidence key, when parse reads it, then it raises MalformedPrediction with a message that contains confidence.
  9. Given a transcript whose last assistant message is the YAML block of decision 1, when OsMe::CLI append runs with --origin agent --autopilot false, then it exits 0, and PredictionLog#records has one row with id session:1, confidence 80, band 80, evidence_before 55, and evidence_after 82.
  10. Given a YAML block with toward: "Keep it in Gate.", when PredictionParser#toward reads it, then it returns "Keep it in Gate.". Given the old text with the line Toward: Keep it in Gate., toward returns the same value.
  11. Given an AI message that holds the YAML block of decision 1 with confidence: 80 and no % anywhere, when ConfidenceExtractor reads it, then the stated percent is 80. Given a message with no YAML block and the line I recommend B, 70% confident., then the stated percent is 70, as before this change.

Owner sketch

module OsMe
  class PredictionParser
    YAML_BLOCK = /^```ya?ml[ \t]*\n(?<body>prediction:.*?)(?:^```[ \t]*$|\z)/m

    def prediction?(text)
      text.match?(YAML_BLOCK) || text.lines.any? { |line| line.match?(CONFIDENCE) }
    end

    def parse(text)
      block = yaml_block(text)
      return [YamlPrediction.new(block).row] if block

      # existing line path, unchanged
    end

    def toward(text)
      block = yaml_block(text)
      return YamlPrediction.new(block).toward if block

      # line path from the blocking ticket, unchanged
    end

    private

    def yaml_block(text) = text.to_enum(:scan, YAML_BLOCK).map { Regexp.last_match[:body] }.last
  end
end

module OsMe
  class PredictionParser
    class YamlPrediction
      def initialize(body)
        @fields = YAML.safe_load(body)['prediction']
        raise MalformedPrediction, 'prediction: is not a mapping' unless @fields.is_a?(Hash)
      rescue Psych::SyntaxError => e
        raise MalformedPrediction, "prediction YAML does not load: #{e.message}"
      end

      def toward = @fields['toward']

      def row
        { id: "#{ID_PREFIX}:1", text: "#{@fields['action']}: #{toward}", confidence: confidence,
          triggers: Array(@fields['why']).join("\n").scan(TRIGGER).uniq }.merge(levers)
      end

      private

      def confidence
        value = @fields['confidence']
        return value if value.is_a?(Integer) && value.between?(0, 100)

        raise MalformedPrediction, "confidence must be an integer 0..100, got #{value.inspect}"
      end

      def levers
        evidence = @fields['evidence'] || {}
        { source: @fields['source'], cost: @fields['cost'], band: @fields['band'],
          evidence_before: evidence['before'], evidence_after: evidence['after'] }.compact
      end
    end
  end
end

Scope and blocking

  • Blocked by: #1289, the os-me ticket that adds PredictionParser#toward(text) for the Toward: value. This ticket extends toward to the YAML block.
  • In scope: plugins/os-me/lib/os_me/confidence_extractor.rb, plugins/os-me/lib/os_me/prediction_parser.rb, plugins/os-me/lib/os_me/prediction_parser/yaml_prediction.rb, and plugins/os-me/lib/os_me/prediction_parser/malformed_prediction.rb. Tests go only under plugins/os-me/test.
  • Orchestrator work, in the same change and outside the pipeline gates: the ~/dev/os-me-store/ENTRY.md, ~/dev/os-me-store/brief.md, and plugins/os-me/skills/predict/SKILL.md edits listed in Approach.
  • Out of scope: conversion of past transcripts or of prediction-log.jsonl; a YAML form for lettered multi-ruling predictions; the wording of the append error "no Prediction with a Confidence line".
  • No ADR: the ADR search found none that records this format (ADR-0272 covers only command names and authority). The old format stays readable, so this change is reversible.

Origin

  • Trigger: Jared ruled on 2026-10-23 that the predictor output becomes YAML, after the S9 clustering finding showed predictions are shown as markdown and parsed by regexes
  • Improvised this session: none
  • Chain: regex-parsed line block ← predictor output format defined in prose in ENTRY.md section 5 ← no machine-readable contract for agent output. Stop at DESIGN (~/dev/os-me-store/ENTRY.md section 5, plugins/os-me/lib/os_me/prediction_parser.rb).
  • Root candidate: none found; searched PREDICTION, PredictionParser, Toward, Confidence regex, ADR-0272
  • Where: plugins/os-me/lib/os_me/prediction_parser.rb; plugins/os-me/skills/predict/SKILL.md; ~/dev/os-me-store/ENTRY.md
  • Session: 4f3f95ea-3c6f-4d23-a0ea-e349d6ab02a5
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/4f3f95ea-3c6f-4d23-a0ea-e349d6ab02a5.jsonl

VERDICT: CREATE (user-approved; backlog search only)

## Problem The predict-mode answer format is prose in `~/dev/os-me-store/ENTRY.md` section 5: a `PREDICTION` header, then `Action:`, `Toward:`, `He would type:`, a `Why:` list, and `Confidence:` lines. Step 1 item 5 of `plugins/os-me/skills/predict/SKILL.md` adds `Source:`, `Cost:`, `Band:`, and `Evidence:` lines. Code reads this text with regexes in `plugins/os-me/lib/os_me/prediction_parser.rb` (`RULING`, `CONFIDENCE`, `WHY`, `TRIGGER`, `LEVER_LINES`). A small change in format, such as bold markup, a moved line, or a percent sign that is not there, gives a wrong or empty row and no error. Jared ruled on 2026-10-23 that agent output that code reads must be machine-readable. Thus the predictor must return YAML. Old transcripts keep the line format and stay read-only, and the Stop-hook recorder and the extractor still read them. Thus the parser must read both formats. Past data is not converted: the Store `prediction-log.jsonl` is already JSON. Readers of the format (grep for `PredictionParser`, `prediction_candidates`, `Confidence:`, `PREDICTION`, `Toward`): - `plugins/os-me/lib/os_me/prediction_parser.rb`: the only parser (`last_prediction`, `prediction?`, `parse`, and `toward` from the blocking ticket). - `plugins/os-me/hooks/cli_appender.rb` (`prediction_shown?`, the Stop-hook ready check) calls `last_prediction`. - `plugins/os-me/hooks/record_prediction.rb` and `plugins/os-me/hooks/prediction_recorder.rb`: the Stop hook. It calls `CliAppender`, which runs `OsMe::CLI` `append`. - `plugins/os-me/lib/os_me/cli/append_request.rb` (`append`) calls `last_prediction` and `parse`, then writes the rows through `PredictionLog`. - `plugins/os-me/lib/os_me/transcript_reader.rb` (`prediction_candidates`) supplies the texts. It does not parse the format. - `plugins/os-me/lib/os_me/prediction_log.rb` reads and writes JSONL rows only. It does not read the transcript format. No change. - `plugins/os-me/lib/os_me/confidence_extractor.rb`, called from `moment_extractor.rb` (`stated_percent`), reads a free-text percent from any AI message. A YAML `confidence: 80` has no `%`, so without a change every new prediction message gives `stated_percent` nil. S10 calibration needs that number, so this ticket makes `ConfidenceExtractor` take the confidence from a YAML prediction block first. - Score run: `plugins/os-me/lib/os_me/predictor.rb` and `scorer.rb` give the prediction text to `judge.rb`, which sends it verbatim to a model through `eval/judge-prompt.md`. No regex. No change. ## Approach Decisions: 1. YAML shape. The predictor returns one fenced block with the info string `yaml`. Its only top key is `prediction:`: ```` ```yaml prediction: action: correct toward: "Keep StepOutcome in Gate; reject the move to Runner." he_would_type: "No, keep it in Gate. Runner must not know step results." why: - "T2: he rejects moves that widen Runner" - "framing 6" confidence: 80 source: precedent cost: low band: 80 evidence: before: 55 after: 82 moved_by: "ruling R12 in rulings.md" ``` ```` `action` is one of accept, correct, or redirect. `why` is a list of one to three quoted strings. `confidence` is an integer from 0 to 100, with no `%`. `source`, `cost`, `band`, and `evidence` are present only when the brief has row labels or the target-confidence step ran. One block holds one ruling, with the id `session:1`. Lettered multi-ruling predictions stay readable only in the old format. 2. Display. Skill step 3 shows the agent's result as is under the heading "Prediction": the YAML block, not changed. The blind reminder line from step 2 goes after the closing fence. Thus the transcript holds the YAML block, and the recorder parses it there. No markdown rendering. 3. Format detection. A text uses the YAML format when it has a line that is exactly ```` ```yaml ```` (or ```` ```yml ````) and the next line starts with `prediction:`. The block body runs to the next ```` ``` ```` line, or to the end of the text. If a text has more than one such block, the last block is used. All other text goes to the existing line path, which does not change. `prediction?` uses only this detection and the existing `CONFIDENCE` line, so it never raises. 4. Malformed block. When a detected block does not load with `YAML.safe_load`, when `prediction:` is not a mapping, or when `confidence` is not an integer from 0 to 100, `parse` and `toward` raise `OsMe::PredictionParser::MalformedPrediction` (an `OsMe::Error`). The message names the fault. The error surfaces in `OsMe::CLI.dispatch`, which changes it to a `Thor::Error`. `append` then exits 1 and writes the message to stderr. In the Stop hook this is a hook error that the session shows. `mark_recorded` does not run, so no row is written and the pending invocation stays unrecorded. Orchestrator work: in the same change, the orchestrator makes these text edits, because the pipeline tests cover only the parser. (a) In `~/dev/os-me-store/ENTRY.md` section 5 (the Store repo, not cc-os), replace the `PREDICTION` line block with the YAML block of decision 1, inside a four-backtick outer fence. State "return exactly this fenced yaml block, nothing before it; quote every string that holds a colon". (b) In `~/dev/os-me-store/brief.md` line 18, replace "under a "## Prediction" heading, with the action, reasons, and a confidence number" with "as the fenced yaml block of ENTRY.md section 5". (c) In `plugins/os-me/skills/predict/SKILL.md`: in step 1, change the `Evidence: <before>% -> <after>%` line instruction to the `evidence:` mapping, and change item 5 to "Add the keys `source`, `cost`, `band`, and `evidence` to the `prediction:` mapping". In step 2, exit 1, put the printed line after the closing fence. In step 3, show the result as is under the heading "Prediction". Then run `bin/refresh-plugins`, and commit the Store edit in `~/dev/os-me-store`. Required work: 1. `PredictionParser` detects the fenced `prediction:` YAML block, and `OsMe::PredictionParser::YamlPrediction` loads it with `YAML.safe_load`. check: present `YAML.safe_load` in `plugins/os-me/lib/os_me/prediction_parser/yaml_prediction.rb` 2. Add `OsMe::PredictionParser::MalformedPrediction < OsMe::Error` in its own file, like `prediction_log/unknown_id.rb`. check: present `class MalformedPrediction < OsMe::Error` in `plugins/os-me/lib/os_me/prediction_parser/malformed_prediction.rb` 3. `PredictionParser#toward` returns the `toward` key of a YAML block through `YamlPrediction#toward` and keeps the line path for old text. check: present `def toward` in `plugins/os-me/lib/os_me/prediction_parser/yaml_prediction.rb` 4. `ConfidenceExtractor` returns the `confidence` of a YAML prediction block when the text has one, else its existing percent path. A malformed block raises `MalformedPrediction`. check: present `PredictionParser` in `plugins/os-me/lib/os_me/confidence_extractor.rb` ## Acceptance criteria 1. Given a text that has the YAML block of decision 1 with `action: correct`, `toward: "Keep it in Gate."`, and `confidence: 80`, and no lever keys, when `PredictionParser#parse` reads it, then it returns one row with `id: 'session:1'`, `text: 'correct: Keep it in Gate.'`, and `confidence: 80`, and the row has no lever keys. 2. Given a YAML block whose `why` list is `["T2: widens Runner", "framing 6", "A5 and T2 apply"]`, when `parse` reads it, then `triggers` is `["T2", "A5"]`. 3. Given a YAML block with `source: precedent`, `cost: medium`, `band: 80`, and `evidence: {before: 55, after: 82, moved_by: "R12"}`, when `parse` reads it, then the row has `source: 'precedent'`, `cost: 'medium'`, `band: 80`, `evidence_before: 55`, and `evidence_after: 82`. 4. Given the old ENTRY.md section 5 text (`PREDICTION`, `Action: accept`, `Toward: ...`, `He would type: ...`, `Why:` with a `- T2 ...` bullet, `Confidence: 70%`), when `parse` reads it, then it returns one row with id `session:1` and confidence 70, as before this change. The existing `prediction_parser_test.rb`, `lever_fields_test.rb`, and `prediction_fields_test.rb` cases pass unchanged. 5. Given texts `["no prediction here", <YAML block text with no "Confidence:" line>, "Done."]`, when `last_prediction` reads them, then it returns the YAML block text, and `prediction?` is true for that text. 6. Given a text with a ```` ```yaml ```` block whose first key is `plan:`, when `prediction?` reads it, then it returns false. 7. Given a YAML block that does not load (for example `why: [unclosed`), when `parse` reads it, then it raises `OsMe::PredictionParser::MalformedPrediction`, and `prediction?` on the same text returns true and does not raise. When `OsMe::CLI` `append` reads a transcript whose last assistant message is that text, it exits 1 with the message on stderr, and the log has no row. 8. Given a YAML block with `confidence: "80%"`, or `confidence: 150`, or no `confidence` key, when `parse` reads it, then it raises `MalformedPrediction` with a message that contains `confidence`. 9. Given a transcript whose last assistant message is the YAML block of decision 1, when `OsMe::CLI` `append` runs with `--origin agent --autopilot false`, then it exits 0, and `PredictionLog#records` has one row with id `session:1`, confidence 80, band 80, evidence_before 55, and evidence_after 82. 10. Given a YAML block with `toward: "Keep it in Gate."`, when `PredictionParser#toward` reads it, then it returns `"Keep it in Gate."`. Given the old text with the line `Toward: Keep it in Gate.`, `toward` returns the same value. 11. Given an AI message that holds the YAML block of decision 1 with `confidence: 80` and no `%` anywhere, when `ConfidenceExtractor` reads it, then the stated percent is 80. Given a message with no YAML block and the line `I recommend B, 70% confident.`, then the stated percent is 70, as before this change. ## Owner sketch ```ruby module OsMe class PredictionParser YAML_BLOCK = /^```ya?ml[ \t]*\n(?<body>prediction:.*?)(?:^```[ \t]*$|\z)/m def prediction?(text) text.match?(YAML_BLOCK) || text.lines.any? { |line| line.match?(CONFIDENCE) } end def parse(text) block = yaml_block(text) return [YamlPrediction.new(block).row] if block # existing line path, unchanged end def toward(text) block = yaml_block(text) return YamlPrediction.new(block).toward if block # line path from the blocking ticket, unchanged end private def yaml_block(text) = text.to_enum(:scan, YAML_BLOCK).map { Regexp.last_match[:body] }.last end end module OsMe class PredictionParser class YamlPrediction def initialize(body) @fields = YAML.safe_load(body)['prediction'] raise MalformedPrediction, 'prediction: is not a mapping' unless @fields.is_a?(Hash) rescue Psych::SyntaxError => e raise MalformedPrediction, "prediction YAML does not load: #{e.message}" end def toward = @fields['toward'] def row { id: "#{ID_PREFIX}:1", text: "#{@fields['action']}: #{toward}", confidence: confidence, triggers: Array(@fields['why']).join("\n").scan(TRIGGER).uniq }.merge(levers) end private def confidence value = @fields['confidence'] return value if value.is_a?(Integer) && value.between?(0, 100) raise MalformedPrediction, "confidence must be an integer 0..100, got #{value.inspect}" end def levers evidence = @fields['evidence'] || {} { source: @fields['source'], cost: @fields['cost'], band: @fields['band'], evidence_before: evidence['before'], evidence_after: evidence['after'] }.compact end end end end ``` ## Scope and blocking - Blocked by: #1289, the os-me ticket that adds `PredictionParser#toward(text)` for the `Toward:` value. This ticket extends `toward` to the YAML block. - In scope: `plugins/os-me/lib/os_me/confidence_extractor.rb`, `plugins/os-me/lib/os_me/prediction_parser.rb`, `plugins/os-me/lib/os_me/prediction_parser/yaml_prediction.rb`, and `plugins/os-me/lib/os_me/prediction_parser/malformed_prediction.rb`. Tests go only under `plugins/os-me/test`. - Orchestrator work, in the same change and outside the pipeline gates: the `~/dev/os-me-store/ENTRY.md`, `~/dev/os-me-store/brief.md`, and `plugins/os-me/skills/predict/SKILL.md` edits listed in Approach. - Out of scope: conversion of past transcripts or of `prediction-log.jsonl`; a YAML form for lettered multi-ruling predictions; the wording of the `append` error "no Prediction with a Confidence line". - No ADR: the ADR search found none that records this format (ADR-0272 covers only command names and authority). The old format stays readable, so this change is reversible. ## Origin - Trigger: Jared ruled on 2026-10-23 that the predictor output becomes YAML, after the S9 clustering finding showed predictions are shown as markdown and parsed by regexes - Improvised this session: none - Chain: regex-parsed line block ← predictor output format defined in prose in ENTRY.md section 5 ← no machine-readable contract for agent output. Stop at `DESIGN` (`~/dev/os-me-store/ENTRY.md` section 5, `plugins/os-me/lib/os_me/prediction_parser.rb`). - Root candidate: none found; searched PREDICTION, PredictionParser, Toward, Confidence regex, ADR-0272 - Where: plugins/os-me/lib/os_me/prediction_parser.rb; plugins/os-me/skills/predict/SKILL.md; ~/dev/os-me-store/ENTRY.md - Session: 4f3f95ea-3c6f-4d23-a0ea-e349d6ab02a5 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/4f3f95ea-3c6f-4d23-a0ea-e349d6ab02a5.jsonl VERDICT: CREATE (user-approved; backlog search only)
Author
Owner

Work started on branch ticket-1292 (os-sdlc implement). #1289 is merged, so the toward method exists.

Work started on branch ticket-1292 (os-sdlc implement). #1289 is merged, so the toward method exists.
Author
Owner

Resolution

Done: Predictor returns a fenced YAML prediction block; PredictionParser reads it and the old line format; ConfidenceExtractor reads YAML confidence; predict skill shows the block verbatim; Store ENTRY.md section 5 and brief.md updated

Evidence: Implementation 155 complete in 6 min 45 s, 10 dispatches, all pass; suite gate green

Follow-ups: #1299 uses PredictionParser#toward on the predictor agent result; no YAML form for lettered multi-ruling predictions (deferred, not filed: no current use); append error text names a Confidence line (deferred, cosmetic)

## Resolution **Done:** Predictor returns a fenced YAML prediction block; PredictionParser reads it and the old line format; ConfidenceExtractor reads YAML confidence; predict skill shows the block verbatim; Store ENTRY.md section 5 and brief.md updated **Evidence:** Implementation 155 complete in 6 min 45 s, 10 dispatches, all pass; suite gate green **Follow-ups:** #1299 uses PredictionParser#toward on the predictor agent result; no YAML form for lettered multi-ruling predictions (deferred, not filed: no current use); append error text names a Confidence line (deferred, cosmetic)
jared closed this issue 2026-10-23 22:27:30 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#1292
No description provided.