uri: repaired and gap 9 (rest of URI slice 5) #132
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Hosts are done;
repairedand gap 9 are later.Source
Acceptance criteria
Dependencies
None known.
Moved from the planning lists of the docs; the design record stays the specification.
[loop:torbscript] intake: in scope (author orion, label loop), source URI.md slice 5, not a duplicate. No dependencies. next: waiting (refine queued, ready buffer full) until 2026-10-10T04:00:00Z
[loop:torbscript] claim refine by session:loop-torbscript-20261024 until 2026-10-24T07:39:00Z
[loop:torbscript] refine: requirements against
docs/design/URI.md(slice 5, sections 6 and 8, gap 9 in section 13) anddocs/language/types/data-or-capsule.mdrule 6. Read-only analysis, no code.[loop:torbscript] decided by the loop: one PR, two Conventional Commits, no seed change.
repaired) is a pure function instd/uriplus tests and docs, part B (gap 9) is a rule of about 15 lines incompiler/src/semantics/checker/derive.trbplus a test and docs. Together roughly 1.5 h, inside the "one PR, one or two commits" size of the definition of ready. Splitting up front is not wanted while the epic rules say so.repairedis a newstdfunction (no syntax, no native, no driver flag, no std name the compiler looks up by string); gap 9 widens when a capsule derivesDecodeand nothing the compiler is built from relies on the refusal. So no two-commit seed dance.Stringwins where there are several" or "a way to name the pair". Decision:Stringwins. It is the smaller rule, URI.md calls it right in every case in the repository, and a capsule that writes as text is what every format wants. It only turns a refusal into a derivation, so it is not a breaking change. Naming the pair stays open for a capsule with several non-Stringpairs (message unchanged for those).UriReference.tryFrom(Path)infallible. It is still fallible today (a UNC server name IDNA refuses isInvalidHost), soPathdoes not gain a second pair now; gap 9 only has to be answered before that day, and this issue answers it.repairedsemantics (URI.md section 6 names "trimmed, backslashes turned, control characters dropped"; the table row that says a browser drops a NUL is not what WHATWG does, it percent-encodes it, andUrialready encodes it as%00). Decision:repaireddoes exactly what the WHATWG URL parser does before it parses, so the result is the address-bar case and nothing stricter:\into/in the part before the first?or#, when the scheme is special (http,https,ws,wss,ftp,file, any case) or the text has no scheme; a\in the query, the fragment or a non-special scheme (git+ssh:,mailto:,urn:) stays.Other C0 controls inside the text (a NUL) are left:
Uri.tryFromencodes them as WHATWG does. The doc comment in URI.md section 6 and the NUL row of its table are corrected to this.Requirements
A.
repaired(commitfeat(uri): repaired(text) for the WHATWG repairs before parsing)public fn repaired(text: String): Stringin a newstd/uri/src/repaired.trb,public use repaired from "./repaired"instd/uri/src/lib.trb. Not in the prelude (URI.md section 16 q2: behinduse ... from "std/uri").repaired(repaired(t)) == repaired(t). Works on bytes/code points without allocating per character more than the existing parser does.Uri.tryFrom(repaired(userInput))?), per thetorbscriptskill canon.B. Gap 9 (commit
fix(checker): a capsule's pair with String is the Decode pair)conversionPairOfinderive.trbreturns the pair whoseSourceisStringwhenconversionSourcesOfhas several and one of them isString; with several and noneString, stillNoneand the message still lists them.derivesThroughPair, the lowering inir/lower/encoding.trband the diagnostic notes (conversionSourcesOfusers) stay consistent: no case where the checker derives and the lowering sees no pair.docs/language/types/data-or-capsule.mdrule 6 anddocs/design/URI.mdgap 9 (closed, with date) and section 8's "second pair" paragraph describe the rule;docs/standard-library/uri.mddocumentsrepaired; URI.md slice 5 state becomes done, section 6's text and table row corrected as above, section 16 q6 untouched.skills/(torb docs skill docs skills), commit with the docs.Acceptance criteria
repaired(" http://example.com/a b ")is"http://example.com/a b";Uri.tryFromof it ishttp://example.com/a%20b.repaired("http:\\\\example.com\\a\\b")is"http://example.com/a/b"(same forhttps,ws,wss,ftp,file, upper-case scheme).repaired("ht\ttp://exa\nmple.com/\r")is"http://example.com/".repaired("git+ssh://host\\path"),repaired("mailto:a\\b@example.com")andrepaired("urn:x:a\\b")keep the backslash;repaired("http://h/a?q=\\x#f\\y")keeps the backslashes after?.repaired("\\\\server\\share")is"//server/share";repaired("")andrepaired(" ")are"".Uri.tryFrom(repaired("http://example.com/a\u0000b"))has path/a%00b(table row corrected).Uri.tryFrom(repaired("http://münchen.de\\x"))ishttp://xn--mnchen-3ya.de/x(IDNA from slice 5 part 1 plusrepaired).TryFrom<String, F>+From<Self>onStringandFrom<Title>/From<Self>onTitlederivesDecode/EncodethroughString(compile and decode round trip in a conformance program); a capsule with two non-Stringpairs still has noDecodeand the message still says "converts both ways withAandB".PathandUriReferencekeep their current pair behaviour (Pathdecodes fromString); nothing instd/loses or gains a derivation unintentionally (full suite green).Test list
std/uri/tests/repaired.test.trb(new): onetestper bullet above (trim, inner tab/newline, backslash for each special scheme and case, non-special scheme, query/fragment, no scheme, empty/blank, NUL, idempotence, the IDNA + backslash combination, repaired +Uri.tryFromround trip).compiler/tests/implementations.test.trb: the test "two types that convert both ways are two pairs" (line ~650) hasStringas one pair, so it would now derive. Rework it to two non-Stringsources (Titleand a second type) so the message stays tested, and add: a capsule withStringplus another pair derivesDecode(no problems), andconversionPairOfpicksString.tests/conformance/encoding-*.trb: one program with theString-plus-other-pair capsule encoded and decoded as JSON in both VM and--native(tier B), next to the existing capsule cases.sh tools/gates.sh a(touchescompiler/src, so it bootstraps) andbis not needed unless the lowering inir/lower/encoding.trbchanges; run in forge CI only, per the contract.Touches / risks
std/uri/src/repaired.trb,std/uri/src/lib.trb,std/uri/tests/repaired.test.trb,compiler/src/semantics/checker/derive.trb,compiler/tests/implementations.test.trb, one conformance program,docs/design/URI.md,docs/language/types/data-or-capsule.md,docs/standard-library/uri.md,skills/.Stringplus another pair and today relies on having noDecode(none known; CI shows it).[loop:torbscript] refine: requirements, acceptance criteria and test list added above, decided by the loop (one PR, two commits, no seed change, String wins for gap 9), label
readyset, next: implement[loop:torbscript] claim implement by session:loop-torbscript-20261024 until 2026-10-24T07:48:27Z
[loop:torbscript] implement: checkpoint (session context limit), branch
loop/132-uri-repairedpushed at1a8c6ed1, no PR yet, next: continue implement.Done: part A function
std/uri/src/repaired.trb(trim U+0000..0020, drop tab/LF/CR,\to/before first?/#for special or no scheme) andpublic use repaired from "./repaired"instd/uri/src/lib.trb, as commit 1feat(uri): repaired(text) for the WHATWG repairs before parsing. Not compiled (no toolchain on the box): CI-verified only.Remaining: (1)
std/uri/tests/repaired.test.trbper the test list (NUL literal is\u{0}, not\u0000); (2) part B incompiler/src/semantics/checker/derive.trb(conversionPairOfpicks theStringpair),compiler/tests/implementations.test.trbrework + new tests, conformance program; (3) docs: URI.md (slice 5 done, section 6 text/NUL row, gap 9, section 8), data-or-capsule.md rule 6,docs/standard-library/uri.md(documentrepaired, addstd/uri/src/repaired.trbto source), regenerateskills/; commit 2fix(checker): a capsule's pair with String is the Decode pair(tests and docs of A may go into commit 1 by amend/rebase); (4) push, open PRCloses #132, comment,ws wt rm. Worktree:code/wt/torbscript-language-132of the orion workspace.[loop:torbscript] implement: checkpoint 2 (session context limit), branch
loop/132-uri-repairedpushed ate048334c, no PR yet, next: continue implement.Done (all CI-verified only, no toolchain on the box):
std/uri/tests/repaired.test.trb(commit24b52305, afixup!of1a8c6ed1); commite048334cfix(checker): a capsule's pair with String is the Decode pair=conversionPairOfpicks theStringpair (and the notes use it), the reworked + new tests incompiler/tests/implementations.test.trb, conformance programtests/conformance/encoding-capsule-text-pair.trbwith.exitand.allocations=unbudgeted: ...(count not measured; PR should say so).Remaining: (1) docs:
docs/design/URI.md(slice 5 done, section 6 text and NUL table row, gap 9 closed with date 2026-10-24, section 8 "second pair" paragraph, theSlugexample at ~line 133 if it changes),docs/language/types/data-or-capsule.mdrule 5/6 (String wins),docs/standard-library/uri.md(documentrepaired, addstd/uri/src/repaired.trbto its source list), maybedocs/standard-library/encoding.md("one conversion pair"); regenerateskills/(torb docs skill docs skills, no toolchain: hand-edit the matchingskills/**copies exactly as the generator would, or leave to CI--checkand say so); put docs in commit 2. (2)git rebase -i --autosquash origin/main-style squash of24b52305into1a8c6ed1(git rebase --autosquash 5d7f7903), thengit push --force-with-lease. (3) open PRCloses #132, comment,ws wt rm torbscript-language-132.[loop:torbscript] implement: PR 465 (
6872007a), next: waiting (forge CI of6872007a)