Ticket graphs

Every ticket as the root of its provenance graph — goal, patch, approval, runs and (as the ticket-class build lands) mandate, manifestations, guarantees, journey, artifacts and children. Rendered through the <<<TicketGraphList>>> tag.

← all ticket-graphs

DONE#344 congruency-go

Port tag ToggleLogin to Go — settle on the #282 go-test harness, NOT a whole-page diff [go-port:tags:tag:ToggleLogin]

goal

Port ONE unit of congruency to Go. ONE. This ticket is deliberately SMALL: porting a whole layer at once is what #230 corrected (~150 units exist; a layer-sized tournament fails at that size). Do not port anything outside this unit. UNIT KEY : go-port:tags:tag:ToggleLogin (the decomposer's idempotency marker — it lives in this ticket's TITLE. Do not edit the title, or the unit will be re-filed as a duplicate.) LAYER : tags — ticket #226 (the tag engine + invocators rendering identical HTML (execute_all_tags in Go)) PHP SOURCE: invocators/tags/login/ToggleLogin.php THE PHP ORIGINAL — the contract: invocators/tags/login/ToggleLogin.php It is a `Tag_Interface` tag; the engine substitutes it wherever <<<ToggleLogin>>> appears in a template, and the gallery renders it standalone at ?page=tags&tag=ToggleLogin (TagList::scan finds it under TAGS_DIR, so that URL resolves). Port THIS tag only — its arguments, its SQL, its markup, and its empty/error state (a tag that degrades gracefully against a missing dependency must degrade IDENTICALLY in Go; see tools/tag_selfcheck.py for what each tag depends on). PAGES WHOSE TEMPLATE EMBEDS <<<ToggleLogin>>>: none today — no Document_Templates row mentions it. DEPENDS ON (build these first — each is its own unit ticket unless marked): - go-port:tags:engine:engine_tag_wrapper - go-port:tags:engine:engine_tag_parser - go-port:tags:engine:engine_tagarguments - go-port:tags:engine:engine_tag_interface THE BUILD — small, and ITERATIVE: 1. Implement ONLY this tag in the Go port, and REGISTER it (see THE GATE below). 2. Run the harness command in THE GATE below. 3. If this tag's line is a BYTE MISMATCH, fix the Go side and go back to 2 — the harness prints the first differing lines. The PHP is the spec: when they disagree, the Go port is wrong; never 'improve' the behaviour here. If the PHP is genuinely defective, file a separate bug ticket and port the defect faithfully. THE GATE — THE ONLY THING THAT SETTLES THIS TICKET. Run the #282 tag-equivalence harness from the repo root (the directory holding registry.json): cd congruency-go && go test ./tags/ -run TestTagEquivalence -count=1 -v SETTLE WHEN THAT COMMAND PASSES with ToggleLogin registered. The harness answers exactly this unit's question — it renders THIS tag through tags.RenderTag (the same entry server.go's handleTagsPage calls) and compares it byte-for-byte against the live PHP's bytes for ?page=tags&tag=ToggleLogin. Paste this tag's own lines as the evidence: --- PASS: TestTagEquivalence/ToggleLogin equivalence_test.go:NNN: IDENTICAL: <N>B byte-for-byte A SKIP IS NOT A PASS. A line reading `--- SKIP: TestTagEquivalence/ToggleLogin` with "no Go port yet" means the tag is NOT registered and NOTHING was measured — and the sweep still exits 0, green. Registering it (below) is what turns that skip into a measurement. Read this tag's own line; never the exit code alone. DO NOT WHOLE-PAGE-DIFF ?page=tags. THIS IS NOT THE GATE, AND A NON-EMPTY DIFF HERE IS NOT A DEFECT IN YOUR PORT: diff <(curl -s 'http://127.0.0.1:8899/?page=tags&tag=ToggleLogin') <(curl -s 'http://127.0.0.1:8900/?page=tags&tag=ToggleLogin') # <-- WRONG GATE That diff is STRUCTURALLY NON-EMPTY for EVERY tag — including tags already merged as byte-perfect: #323 measured ~6205B of difference on CategoryView, TreeView and TicketList, all three of them correct. The two sides are not the same kind of document: the PHP URL returns a full CMS page (Controller::control's chrome, then the gallery, then the tag's bytes, then the template tail), while the Go server wraps the tag engine's render in its OWN frame and says so in its source — congruency-go/server.go:820-823 emits the comment "the doctype/title/h1 frame around it is this server's own: the CMS Controller::control() page chrome is still not reproduced here." The difference is that missing chrome. It is a known, separate, un-ported piece of the server; it is not this tag, it is not yours to fix here, and no correct port can ever make that diff empty. Settling on it is what stalled the tag fan-out and forced #310/#311/#312 to be hand-harvested (#323). The harness exists precisely because the tag's bytes are a SLICE of that page: it cuts the slice with TagList.php's own anchors (:62 and :76) and a page tail it MEASURES at run time, fetches PHP twice around the Go render so a concurrent write shows up as VOLATILE instead of a false failure, and compares only the tag. That is the comparison this ticket is asking for. Read congruency-go/tags/equivalence_test.go before arguing with its verdict. REGISTERING ToggleLogin (the gate cannot pass until you do this): Add an init() to your tag's own file in congruency-go/tags/, exactly as every ported tag does (congruency-go/tags/contenttag.go:151-153 is a one-tag example, and engine.go:1374-1385 registers the ten #226 landed together): func init() { Register("ToggleLogin", func(e *Engine, a *TagArguments) Tag { return &ToggleLoginTag{e: e, args: a} }) } Register is the registry's ONLY writer (engine.go:1342-1368) and it PANICS on a duplicate name, so register in exactly ONE place. Registering is what flips tags.IsPorted("ToggleLogin") to true, and THAT is what makes the harness measure this tag instead of skipping it — no edit to congruency-go/tags/equivalence_test.go is needed, or wanted. TAGS THIS TAG DEPENDS ON: none. Its own output embeds no other tag's invocation (derived from its PHP source, comments excluded — see the decomposer's tag_emits()), so nothing else has to be registered before the gate can measure it. WHAT THE HARNESS DOES NOT MEASURE — port these anyway, do not bolt them onto the gate: * ARGUMENTS. The gallery constructs the selected tag standalone (`new $sel(null)`, TagList.php:67-68), so the sweep measures the ARGUMENT-LESS render only. If this tag takes arguments, port them faithfully against the PHP source and the argument forms the pages above use; a Go unit test of your own is the right place to pin them. * THE IN-PAGE SUBSTITUTION SITES. Diffing ?page=<id> on both servers is the same broken whole-page comparison as above and fails for the same chrome reason. Those pages settle on their own page units, once the chrome is ported. IF THE HARNESS ITSELF SKIPS EVERYTHING ("no API key", "state db absent", "server unreachable", "TAGS_DIR lists no tags") it measured NOTHING and this ticket does not settle. Its four guards are deliberate — it never false-fails in CI — so a green run that skipped is not evidence. Fix the environment: boot the PHP original the way tools/serve.py does ( cd checkouts/current/congruency && /Users/stevenpeterson/code/installed/jazz-project/congruency/tooling/congruencey-harness/php/php -S 127.0.0.1:8899 boot/router.php ) and re-run. The harness resolves the db, the app root and the URL itself; its overrides are $CONGRUENCY_API_KEY, $CONGRUENCY_APP_ROOT, $CONGRUENCY_EQUIV_DB, $CONGRUENCY_TAGS_URL and NOTHING ELSE — in particular CONGRUENCY_SQLITE is NOT one of them, so prefixing the gate with it changes nothing and would quietly measure the default database. SETTLING: this ticket settles when — and only when — the harness command in THE GATE above PASSES for this tag. Paste the command you ran and this tag's own PASS/IDENTICAL line as the evidence. Do NOT settle on a whole-page diff of ?page=tags, and do NOT refuse a correct port because that diff is non-empty: it is non-empty for every tag, always, for a reason THE GATE explains and no port can fix. A SKIP is not a PASS. Kind is `build` (a pair: coder + adversarial tester). This unit gets a tournament only if someone judges it genuinely worth one — that is the exception on #230, not the default. Filed mechanically by checkouts/current/congruency/tools/go_port_decomposer.py under ticket #230.

patch

none

approval

unapproved

runs

no runs recorded

mandate (clauses)

not yet recorded — lands with the ticket-class build

manifestations

not yet recorded — lands with the ticket-class build

guarantees

not yet recorded — lands with the ticket-class build

journey (blunders & successes)

not yet recorded — lands with the ticket-class build

artifacts (forge)

not yet recorded — lands with the ticket-class build

source (forge tree)

browse congruency source (forge-parked tree)

children

not yet recorded — lands with the ticket-class build