From e55deb91418398b31e0ed902d3abddaf2a53c12a Mon Sep 17 00:00:00 2001 From: Morabbin Date: Thu, 20 Aug 2026 22:23:06 +0100 Subject: [PATCH] Strip trailing _query_source column before header validation session_store_sql supplements local-store results with a trailing _query_source column that materialize-session-query.py's exact header check rejected with "unexpected discovery result column _query_source". Drop the column in table_rows only when it is genuinely the last column in the header, using a single right-hand split so embedded " | " sequences in earlier values (e.g. arguments_json) are preserved. Unknown extra columns and a non-trailing _query_source are still rejected by the unchanged header equality check. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../scripts/materialize-session-query.py | 9 ++ .../tests/test_materialize_session_query.py | 149 ++++++++++++++++++ 2 files changed, 158 insertions(+) diff --git a/plugins/repo-dreamer/skills/repository-skill-forge/scripts/materialize-session-query.py b/plugins/repo-dreamer/skills/repository-skill-forge/scripts/materialize-session-query.py index 92b5a9a..c8750b7 100755 --- a/plugins/repo-dreamer/skills/repository-skill-forge/scripts/materialize-session-query.py +++ b/plugins/repo-dreamer/skills/repository-skill-forge/scripts/materialize-session-query.py @@ -256,6 +256,15 @@ def table_rows(content: str) -> tuple[list[str] | None, list[str]]: raise ValueError( f"session_store_sql row count mismatch: expected {expected}, found {len(rows)}" ) + if header and header[-1] == "_query_source": + # session_store_sql supplements local-store results with a trailing + # _query_source column. It is not part of any expected schema, so drop + # it here (only when it is genuinely the last column) before header + # validation runs. A single right-hand split removes only that final + # Markdown cell, leaving embedded " | " sequences in earlier values + # (e.g. arguments_json) untouched. + header = header[:-1] + rows = [row.rsplit(" | ", 1)[0] for row in rows] return header, rows diff --git a/plugins/repo-dreamer/skills/repository-skill-forge/tests/test_materialize_session_query.py b/plugins/repo-dreamer/skills/repository-skill-forge/tests/test_materialize_session_query.py index 775ea36..ade86e4 100644 --- a/plugins/repo-dreamer/skills/repository-skill-forge/tests/test_materialize_session_query.py +++ b/plugins/repo-dreamer/skills/repository-skill-forge/tests/test_materialize_session_query.py @@ -759,6 +759,155 @@ def test_explicit_exit_code_drives_primitive_outcome(self) -> None: self.assertEqual(1, primitives[0]["exitCode"]) self.assertEqual("failure", primitives[0]["outcome"]) + def test_table_rows_without_query_source_column_is_unchanged(self) -> None: + content = "\n".join( + [ + "1 row(s) returned:", + "", + "| session_id | updated_at |", + "| --- | --- |", + "| session-1 | 2026-08-01T00:00:00Z |", + ] + ) + + header, rows = materializer.table_rows(content) + + self.assertEqual(["session_id", "updated_at"], header) + parsed = materializer.parse_rows("discovery", header, rows) + self.assertEqual( + [{"session_id": "session-1", "updated_at": "2026-08-01T00:00:00Z"}], + parsed, + ) + + def test_table_rows_strips_trailing_query_source_column(self) -> None: + content = "\n".join( + [ + "1 row(s) returned:", + "", + "| session_id | updated_at | _query_source |", + "| --- | --- | --- |", + "| session-1 | 2026-08-01T00:00:00Z | cloud |", + ] + ) + + header, rows = materializer.table_rows(content) + + self.assertEqual(["session_id", "updated_at"], header) + self.assertEqual(["session-1 | 2026-08-01T00:00:00Z"], rows) + parsed = materializer.parse_rows("discovery", header, rows) + self.assertEqual( + [{"session_id": "session-1", "updated_at": "2026-08-01T00:00:00Z"}], + parsed, + ) + + def test_table_rows_rejects_unknown_trailing_column(self) -> None: + content = "\n".join( + [ + "1 row(s) returned:", + "", + "| session_id | updated_at | extra_column |", + "| --- | --- | --- |", + "| session-1 | 2026-08-01T00:00:00Z | mystery |", + ] + ) + + header, rows = materializer.table_rows(content) + + self.assertEqual(["session_id", "updated_at", "extra_column"], header) + with self.assertRaisesRegex( + ValueError, "unexpected discovery result columns" + ): + materializer.parse_rows("discovery", header, rows) + + def test_table_rows_rejects_query_source_when_not_trailing(self) -> None: + content = "\n".join( + [ + "1 row(s) returned:", + "", + "| session_id | _query_source | updated_at |", + "| --- | --- | --- |", + "| session-1 | cloud | 2026-08-01T00:00:00Z |", + ] + ) + + header, rows = materializer.table_rows(content) + + self.assertEqual(["session_id", "_query_source", "updated_at"], header) + with self.assertRaisesRegex( + ValueError, "unexpected discovery result columns" + ): + materializer.parse_rows("discovery", header, rows) + + def test_query_source_stripping_preserves_embedded_pipes(self) -> None: + content = "\n".join( + [ + "1 row(s) returned:", + "", + "| session_id | tool_call_id | tool_name | arguments_json | " + "exit_code | completed_at | _query_source |", + "| --- | --- | --- | --- | --- | --- | --- |", + '| session-1 | call-1 | bash | {"command":"printf \\"a | ' + 'b\\\\n\\""} | 0 | 2026-08-01T00:00:01Z | cloud |', + ] + ) + + header, rows = materializer.table_rows(content) + + self.assertEqual( + [ + "session_id", + "tool_call_id", + "tool_name", + "arguments_json", + "exit_code", + "completed_at", + ], + header, + ) + parsed = materializer.parse_rows("tool-calls", header, rows) + self.assertEqual(1, len(parsed)) + self.assertEqual( + {"command": 'printf "a | b\\n"'}, + json.loads(parsed[0]["arguments_json"]), + ) + self.assertEqual(0, parsed[0]["exit_code"]) + self.assertEqual("2026-08-01T00:00:01Z", parsed[0]["completed_at"]) + + def test_table_rows_strips_query_source_with_zero_rows(self) -> None: + content = "\n".join( + [ + "0 row(s) returned:", + "", + "| session_id | updated_at | _query_source |", + "| --- | --- | --- |", + ] + ) + + header, rows = materializer.table_rows(content) + + self.assertEqual(["session_id", "updated_at"], header) + self.assertEqual([], rows) + self.assertEqual([], materializer.parse_rows("discovery", header, rows)) + + def test_malformed_row_missing_query_source_cell_raises_downstream( + self, + ) -> None: + content = "\n".join( + [ + "1 row(s) returned:", + "", + "| session_id | updated_at | _query_source |", + "| --- | --- | --- |", + "| session-1 | 2026-08-01T00:00:00Z |", + ] + ) + + header, rows = materializer.table_rows(content) + + self.assertEqual(["session_id", "updated_at"], header) + with self.assertRaises(ValueError): + materializer.parse_rows("discovery", header, rows) + if __name__ == "__main__": unittest.main()