Skip to content
This repository was archived by the owner on Oct 5, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ the section in the pull request that bumps the version: a one-line summary
paragraph, then one bullet per change a user or operator would notice. Keep
each paragraph and bullet on one line; release pages render line breaks.

## 0.19.1 - 2026-10-01

Page claim checks exclude script and stylesheet bodies with HTML closing-tag whitespace or trailing attributes.

- Keep hidden script and style text out of page evidence when closing tags contain HTML whitespace or trailing attributes, or the fetched page ends inside a raw-text body.
- Preserve visible text in similarly named custom elements and retain existing fetch and evidence limits.

## 0.19.0 - 2026-09-30

Sys1 can update supported global CLI installations before work starts.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hraness/sys1",
"version": "0.19.0",
"version": "0.19.1",
"description": "Sys1 gives coding agents tools to review code, check completion claims, and get structured answers from Jev or a local model.",
"type": "module",
"license": "MIT",
Expand Down
5 changes: 4 additions & 1 deletion src/verify/evidence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,10 @@ export async function fetchPage(
}
const text = new TextDecoder().decode(whole);
evidence.ok = true;
evidence.excerpt = text.replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ")
// Raw-text bodies are not visible evidence. Accept HTML close-tag whitespace
// and discard an unfinished body when the bounded page ends inside it.
evidence.excerpt = text.replace(/<script(?=[\t\n\f\r />])[^>]*>[\s\S]*?(?:<\/script(?=[\t\n\f\r />])[^>]*>|$)/gi, " ")
.replace(/<style(?=[\t\n\f\r />])[^>]*>[\s\S]*?(?:<\/style(?=[\t\n\f\r />])[^>]*>|$)/gi, " ")
.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim().slice(0, EVIDENCE_LIMITS.maxPageBytes);
return evidence;
} catch {
Expand Down
2 changes: 1 addition & 1 deletion src/version.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const SYS1_VERSION = "0.19.0";
export const SYS1_VERSION = "0.19.1";
35 changes: 35 additions & 0 deletions test/verify-page-excerpt.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { expect, test } from "bun:test";
import { EVIDENCE_LIMITS, fetchPage } from "../src/verify/evidence.ts";

for (const tag of ["script", "style"]) {
for (const whitespace of [" ", "\t", "\n", "\r", "\f", " \n\t"]) {
test(`page excerpt excludes ${tag} with close-tag whitespace ${JSON.stringify(whitespace)}`, async () => {
const page = await fetchPage("https://example.com", async () => new Response(
`<p>Visible before.</p><${tag.toUpperCase()} type="text/plain">hidden-evidence-canary</${tag}${whitespace}><p>Visible after.</p>`,
));
expect(page.ok).toBe(true);
expect(page.excerpt).toBe("Visible before. Visible after.");
});
}
for (const tail of ["/", " ignored", " ignored=\"value\""]) {
test(`page excerpt retains following text after ${tag} end-tag tail ${tail}`, async () => {
const page = await fetchPage("https://example.com", async () => new Response(
`<p>Before.</p><${tag}>hidden-evidence-canary</${tag}${tail}><p>After.</p>`,
));
expect(page.excerpt).toBe("Before. After.");
});
}
test(`page excerpt excludes ${tag} body cut off by the byte cap`, async () => {
const page = await fetchPage("https://example.com", async () => new Response(
`<p>Visible.</p><${tag}>` + "hidden-evidence-canary ".repeat(EVIDENCE_LIMITS.maxPageBytes) + `</${tag}>`,
));
expect(page.excerpt).toBe("Visible.");
});
}

test("similarly named custom elements retain their visible text", async () => {
const page = await fetchPage("https://example.com", async () => new Response(
"<script-example>Visible example.</script-example><style-guide>Visible guide.</style-guide>",
));
expect(page.excerpt).toBe("Visible example. Visible guide.");
});
Loading