Skip to content

feat(planning): bring the one-on-one interview page in line with the shared page #8633

Open
0 of 4 issues completed

Description

@kyle-sexton

Problem

The shared interview page (plugins/planning/shared) now has the patterns the owner settled during live dogfooding: the one-column question screen, the folded Discussion and Claude sections, the composer kit, the Inbox, and phone keyboard handling. The one-on-one interview web page did not get them. The owner said this would need a separate session to tailor the existing page.

Proposal

One session that audits the one-on-one page against the shared page and moves the shared primitives into it (or makes both pages use one copy), then works through the open follow-ups listed below.

Acceptance

Related

Activity

  1. added
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 20, 2026
  2. github-actions commented on Oct 20, 2026

    @github-actions
    Contributor

    Proposed work class: work-class: structural
    Basis: automated intake triage; the lanes App applied this class.

    Size: Large
    Complexity: Medium
    Uncertainty: Known
    Flags: none
    Blocked by: none

    Decision recorded. The owner answered in the Refinement session (2026-10-25), deciding the open items below on the facts:

    go with whatever the facts/data/metrics + /discovery:research says and ensure we're aligned with SOLID, DRY/SSOT principles

    I should only ever be in the loop ONLY when necessary (intent/vision changed, something came up during implementation that impacts trajectory/alignment, OR a high security risk) - I've covered this all before

    [quote truncated; the full decision is at the link]

    #8633 (comment)

    This decision settles the open questions: the issue is split per phase with #8633 as tracker, Phase 4 uses the union markdown dialect, the #8089 SHA source is out of scope, and out-of-scope findings close here with a written reason. The work is large, so it is tracked here and done in the split issues.

    Automated triage, applied by the lanes App.

  3. added
    needs-humanHuman-in-the-loop required; autonomous sessions must not resolve items carrying this.
    and removed
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 20, 2026
  4. kyle-sexton commented on Oct 21, 2026

    @kyle-sexton
    MemberAuthor

    Scope addition: move the shared validator the one-on-one page and the shared page both use into lib/, so the two pages enforce the same question shape from one copy.

  5. kyle-sexton commented on Oct 22, 2026

    @kyle-sexton
    MemberAuthor

    Design record for this effort, moved here from a local working file so the issue holds it. Line numbers cite main as of 2026-10-22 and may have drifted.

    DESIGN.md

    One source of truth for question-shape knowledge (#8633)

    Base: origin/main bd05b7b973. Every file:line below is against that commit and relative to
    plugins/planning/ unless it starts with docs/. Read-only design; nothing is built yet.

    Owner decision (2026-10-22, in session): "true dedupe, SSOT, progressive disclosure, whatever that
    shakes out to". Goal: each piece of question-shape knowledge has one authoritative representation
    that every lane and page consumes.

    Grounding

    • DRY: "Every piece of knowledge must have a single, unambiguous, authoritative representation
      within a system"; "DRY is about the duplication of knowledge, of intent", tested by whether one
      change needs edits in several places. Hunt & Thomas, The Pragmatic Programmer, 20th anniversary
      ed., DRY topic, publisher excerpt https://media.pragprog.com/titles/tpp20/dry.pdf (read in
      .work/owner-questions-research/shared-ui-code/RESEARCH-findings.md:154-163, claim 4, HIGH).
      So the unit is knowledge, not code shape: two functions with the same name and different meaning
      stay apart (section 1, "not the same knowledge").
    • Qualifier: Metz, "The Wrong Abstraction" https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction
      (same findings file:180): a shared primitive that grows per-page flags is the wrong abstraction.
      Page-specific behavior stays on its page.
    • In-plugin sharing: ADR 0019 "Intra-plugin sharing: one committed copy, no sync script"
      (docs/adr/0019-share-code-across-plugins-by-vendoring-with-a-sync-gate.md:75-86): one committed
      copy, no sync script, no drift gate, a plugin version bump per change. The 2026-10-02 amendment
      (same file:88-102, generated copies with --check) is for cross-plugin copies and does not apply
      here.
    • Progressive disclosure: model-facing rules live once in skills/interview/context/question-shape.md;
      lane docs point to it. skills/interview/SKILL.md stays byte-identical (standing items), so the
      Stance rules it already holds (Withheld SKILL.md:141,189; Basis SKILL.md:140) remain their
      source and question-shape.md points to them.

    Python and the browser cannot share one file

    A served JS file cannot dedupe a rule Python also encodes. Each row in section 2 picks one of:

    • (S) server-derived: the rule lives in one Python function; each server ships its result as a
      field in the page's data, and the browser only reads it. One implementation. Precedent: the 1:1
      server already derives state, revising, upstreamChanged, answered in memory before
      sending (surface/server.py:866-890); the shared server builds a per-viewer snapshot
      (shared/session.py:6290).
    • (B) served browser file: knowledge only the browser has (layout, composer, keyboard, rendering)
      lives in one classic script exposing one global (as shared/web/core.js does), served by both
      servers (Q2 decision: STATIC entry shared/server.py:75-85, dispatch :774-775; one route in
      surface/server.py route_get :1117-1155, whose CSP already allows 'self' scripts and styles
      :76-77).
    • (J) JSON Schema: types, enums and limits live in shared/schema/question-shape.schema.json;
      other schemas $ref it (the shared state and ops schemas already do: state.schema.json:572-579,
      ops.schema.json:250-257).
    • (D) skill doc: rules the model follows when writing a question.

    Python home for (S): surface/question_shape.py, next to surface/schema.py. Both servers already
    import from surface/ (shared/session.py:44-50 puts it on sys.path for schema.py; round.py:95
    imports it), so this adds no new path. Basis: fewest moving parts, judgment.

    1. Inventory

    Agree: Y = every representation says the same; N = they disagree; 1 = one representation only.

    # Knowledge Where it is represented today Agree
    K1 Field set and types of a question shared/schema/question-shape.schema.json:1-40; shared/schema/state.schema.json:565-588 (refs K1); shared/schema/ops.schema.json:245-259 (refs K1); surface/schema/questions.schema.json:254-293 (own copy, no ref); question-shape.md:18-29 N: page schema re-declares every field without limits
    K2 Per-lane field names (title/facts/commits on the page; text/context/format shared) question-shape.md:35-41 "Per lane"; surface/schema/questions.schema.json:269-274; surface.md:75-77 op fields; consumers surface/index.html (q.title, q.facts), shared/web/core.js/app.js (q.text, q.context) Y (one mapping, in the doc)
    K3 short length cap 80: question-shape.schema.json short.maxLength, question-shape.md:23, shared/session.py:2400. 500: surface/server.py:49 LINE_CAP, surface/round.py:133, surface.md:93 N
    K4 Alternative shape: keys and tradeoff a-d enum + tradeoff: question-shape.schema.json alternative, question-shape.md:28, shared/session.py:2413-2420. Any string key, no tradeoff, additionalProperties: false: surface/schema/questions.schema.json:189-197 N
    K5 Alternative count Shared: 2-3, shared/session.py:2409-2412, question-shape.md:41. Page: at least 2, exactly 1 if binary, surface/round.py:354-373, round.py:56,64, surface.md:217 (R-I). Schema maxItems: 4 in K1 Y per lane (lane-specific, documented)
    K6 An alternative must not restate the recommendation Doc: question-shape.md:28. Three code definitions: refuse on whole-word containment surface/round.py:262-280 (check_rec_alts, reply/revise); warn on equality after folding (recommended) surface/round.py:585-595 + :626-630 (norm_alt, add); fold into Accept on the page surface/index.html:1141-1145 (normAlt, altsOf). Shared lane: none (shared/session.py:2404-2420 accepts any distinct-key alternatives; each becomes a card :2520) N (three rules, one lane without one)
    K7 Withheld: recommendation = asked open, never on a card Rule: SKILL.md:141,189; question-shape.md:26. Page: surface/index.html:719 (withheld), used :1146-1151 (no Rec/Hedged choices) and :1199 heading. Shared: none; shared/session.py:2516-2520 makes a rec card from any recommendation and shared/web/app.js:5722 labels it "Claude recommends" N (shared lane breaks the rule)
    K8 basis content and how it reads Rule: question-shape.md:27 (opens Checked against:, then Basis: and reasoning), SKILL.md:140. Page: "Why" fold, markdown, surface/index.html:1200. Shared: prefixes Basis: to the whole field, shared/web/app.js:5730; fixtures hold "basis": "Checked against: …" (shared/tests/fixtures) so the page shows Basis: Checked against: … N (shared label precedes the Checked against: line the rule puts first)
    K9 Something else / OTHER option shared/session.py:186-187 (OTHER_OPTION, label "Something else…"), :434-467 (rule check), :2454-2455 (refuse if written); state.schema.json option description + id enum; question-shape.md:102-104; browser reads the server label and hard-codes the id "other" (shared/web/core.js:168,192,1222,1226). Page lane: no OTHER; "Own answer" choice instead (surface/index.html:1149) Y within the shared lane; the page's Own answer is a different decision kind (see K15)
    K10 Option counts per format question-shape.md:95-98 (choice 2-4, multi 2-8, rank 3-6); shared/session.py:185 OPTION_COUNTS; state.schema.json format (stored, OTHER included: choice 2-5, multi 2-9, rank 3-7; ops.schema.json:259 reuses it for input) Y on the numbers, stated three times; the stored minItems is slack by one (stored options always add OTHER)
    K11 Formats and purposes question-shape.md:80-99; shared/session.py:182-183; state.schema.json purpose, format; shared page branches on q.format (app.js isChoice, :490). Page lane: no formats (decisions only) Y (shared lane only)
    K12 Composer (textarea growth, send key, counter, drafts, mentions) Shared: composer() shared/web/app.js:667-700+, grow() :854-860, CSS shared/web/app.css:538-541,795,1219-1232. Page: grow() surface/index.html:1284 (40% of window, no counter or send-key hint); answer box renderAnswer :1231-1268 N (two implementations, different behavior)
    K13 Phone keyboard handling Shared: fitViewport pins to the visual viewport, --kb, data-kb shared/web/core.js:1605-1630; reveal-on-focus shared/web/app.js:862,873. Page: none 1 (page lacks it)
    K14 Markdown / inline rendering Shared: DOM builder rich/inline/links shared/web/app.js:536-620 (paragraphs, - lists, **bold**, `code`, bare links). Page: string builder md/inline surface/index.html:578-617 (headings, quotes, lists, links, issue refs :583) N (two dialects)
    K15 Decision vocabulary (accept, alt, own, defer, hedged) surface/index.html:536-537 (LABEL, DEC), surface/schema/responses.schema.json, surface/exporters.py 1 (page lane only)
    K16 Answer line text Page answerLine(q) "You answered …" surface/index.html:704; shared answerLine(a) card text or file count shared/web/app.js:510 different knowledge (see below)
    K17 GitHub owner/repo pattern shared/session.py:253 (its comment names copies in state.schema.json:148 and shared/web/app.js:562); page issue-link regex surface/index.html:583 N (four places; page regex differs)
    K18 Question id Q<N> and dependsOn earlier-only question-shape.schema.json questionId; shared/session.py:2425-2430; surface/round.py (dependsOn checks); question-shape.md:18,29 Y

    Not the same knowledge (no SSOT; same name, different meaning): answerLine, inline, grow
    (K12 merges the behavior, not these two helpers as written), who, step, post, select,
    row, num (the 21-name intersection of the two pages' function names). Merging them would be
    Metz's wrong abstraction.

    2. Source of truth per piece, and how the rest derive

    # SSOT Kind Consumers derive by
    K1 shared/schema/question-shape.schema.json J surface/schema/questions.schema.json question properties $ref its $defs for types and limits; lane extras (facts, commits, binary, state fields) stay local. Blocker: surface/schema.py:46-51 _by_id searches only loaded registries, so round.py and surface/server.py must load shared/schema once (schema.registry(SHARED_SCHEMA_DIR)) before validating. Moving the file to a plugin-level schema/ instead would touch shared/tests/test_schema_shapes.py:27, shared/tests/tracer.test.sh:8 and every $id; not recommended
    K2 question-shape.md "Per lane" D No rename. Renaming title→text on the page would break files the page lane still reads (surface/test_schema.py:114, v2.1 files without a schema version). The mapping table is the single representation
    K3 the schema short.maxLength J Page schema refs it; round.py:133 drops its own short cap (schema enforces). Value is an owner choice (P1)
    K4 the schema alternative J Page schema refs it; tradeoff becomes allowed on the page, and the page shows it under Alternatives. Key enum on old page files is an owner choice (P4)
    K5 lane rules stay lane-local D + code surface.md:217 R-I and lane-shared.md keep their counts; question-shape.md:41 keeps the shared count once. No change
    K6 one function restates(alt_text, rec) in surface/question_shape.py S round.py check_rec_alts and restates_recommendation/norm_alt call it; shared/session.py input parsing calls it; both servers ship alternatives[i].restates: true in page data; surface/index.html altsOf reads the flag instead of normAlt. Which definition, and refuse vs warn, is an owner choice (P2)
    K7 one function withheld(rec) in surface/question_shape.py; rule text stays SKILL.md:189 S 1:1 server ships withheld: true; surface/index.html:719 reads it. shared/session.py:2516-2520 makes no rec card for a withheld recommendation; the shared snapshot ships withheld; app.js shows the Withheld: text as the question's open note. Alternatives on a withheld shared question: owner choice (P3)
    K8 question-shape.md:27 D Shared page drops its Basis: prefix and renders the field as written (it already opens Checked against: and carries its own Basis: label), through the K14 renderer, folded like the page's "Why". Follows from the written rule
    K9 shared/session.py:186 OTHER_OPTION S Already the source; the browser reads the label from options. The "other" id literal in core.js becomes one constant in the served file (B). Page lane: no change
    K10 shared/session.py:185 OPTION_COUNTS + the schema S/J question-shape.md:95-98 keeps the model-facing numbers (D, the model needs them); a Python test asserts the doc table, OPTION_COUNTS and the stored schema bounds agree (stored = counts + 1). Tighten stored minItems to counts + 1
    K11 shared/session.py:182-183 + schema S/J No change; shared lane only
    K12 shared/web/question-shape.js (B) + shared/web/question-shape.css B composer() and grow() move out of app.js into the served file; app.js calls the global; surface/index.html loads both files (new route + <link>) and wires its answer and note textareas to the same composer. Page-specific send actions stay as callbacks
    K13 same served file B fitViewport moves out of core.js:1605-1630 into the served file; both pages call it. The 1:1 page's layout must consume --vv-h/--kb
    K14 same served file: one safe DOM renderer B One dialect covering both pages' needs (headings and quotes from the page; mentions and bare links from the shared page; issue refs when the session names a repo). surface/index.html md/inline and app.js rich/inline/links are removed. Dialect is an owner choice (P6)
    K15 page-lane only — No SSOT change; written down as a page-specific difference (#8633 acceptance allows it)
    K16 not the same knowledge — No change
    K17 shared/session.py:253 REPO S Shared page reads a server-validated value instead of its own regex; state schema keeps its pattern (J, validation); page issue links use the K14 renderer with the same pattern
    K18 schema + question-shape.md J/D No change

    Docs (progressive disclosure): question-shape.md holds every model-facing rule once and points to
    SKILL.md Stance for Withheld and Basis. lane-page.md, surface.md, lane-shared.md point to it
    and keep only lane-specific rules (R-I count, op fields, purpose/format inference already in
    question-shape.md). Today they mostly point already (lane-shared.md:153,328,334); surface.md:93
    restates a cap that K3 resolves.

    3. Behavior changes unification forces

    # Change Kind
    C1 Shared lane: a Withheld: text question shows no "Claude recommends" card; its text shows as an open note Follows from SKILL.md:189 ("asked open, never on a card"; "on the page its recommendation field carries the Withheld: text"). Fixes the bug at shared/session.py:2516-2520
    C2 Shared lane: whether a withheld question keeps 2-3 alternative cards, or takes none (session.py:2409-2410 requires them with any recommendation) New product choice (P3)
    C3 Shared lane: an alternative that restates the recommendation is refused (or warned, or folded) like the page lane Rule exists (question-shape.md:28 "none restates the recommendation"); which definition and refuse vs warn is a new product choice (P2)
    C4 Page lane: one restates definition replaces three; files that passed the old warn-only check may now be refused on revise, and the page's fold uses the server flag Part of P2
    C5 Shared page shows basis as written (no extra Basis: prefix), rendered and folded Follows from question-shape.md:27
    C6 Page lane: short cap becomes one number New product choice (P1): 80 (question-shape.md:23) vs 500 (surface.md:93); two written rules conflict
    C7 Page lane: alternatives accept tradeoff and show it Follows from question-shape.md:28 ({key, text, tradeoff})
    C8 Page lane: alternative keys limited to a-d New product choice (P4): old page files with other keys would fail validation
    C9 1:1 page adopts the shared composer (send key hint, counter, drafts per question, growth relative to the pane) Follows from #8633 acceptance ("same … composer … or the differences written down") and the owner's dedupe decision; the 1:1 page already sends with Ctrl/Cmd+Enter (surface/index.html:2267) and runs single-key shortcuts only outside text boxes (:522), so the keys mostly agree; whether the composer's per-field send replaces the page's one document-level Ctrl+Enter handler (:2263-2283) is a new product choice (P5)
    C10 1:1 page adopts visual-viewport pinning on phones Follows from #8633 acceptance ("phone keyboard behavior")
    C11 Both pages render markdown with one dialect New product choice (P6): the page loses or the shared page gains headings, quotes and issue refs
    C12 Question-screen layout (one-column, folded Discussion and Claude sections) on the 1:1 page Named in #8633 acceptance but it is page layout, not question-shape knowledge; out of this design's scope; scope it with P5/P6 or as its own phase (P7)

    4. Phased build plan (one PR each)

    Common to every phase: worktree under <worktrees>/ccp-shared-<slug>; planning version
    bump per ADR 0019:75-86 only if the release flow needs it (check how .changes/planning fragments
    drive versions first); a .changes/planning fragment; SKILL.md untouched. Python suites:
    plugins/planning/shared/tests/test_*.py and plugins/planning/surface/test_*.py. Browser suites one
    at a time host-wide, only when pgrep -x chrome-headless prints nothing: shared as
    env UI_JOBS=2 nice node plugins/planning/shared/tests/<suite>.js; 1:1 as
    bash plugins/planning/surface/surface-checks.sh --part main|ui-c|journey. Any interview doc edit
    also runs tests/interview-defenses.test.sh and tests/reattach-slice.test.sh. Every phase that
    edits surface/ is the other lane's: check ListAgents and message its owner first; say so in the PR.

    Phase 1: schema SSOT (K1, K3, K4, K10). Needs P1, P4.

    • Acceptance: questions.schema.json question properties $ref question-shape $defs; round.py
      and surface/server.py load shared/schema before validating; round.py:133 short cap gone;
      stored minItems = counts + 1; a test asserts doc table = OPTION_COUNTS = schema bounds - 1.
    • Tests: both Python suites (surface/test_schema.py, test_round.py, test_server.py,
      shared/tests/test_schema_shapes.py); shared/tests/tracer.test.sh (it scopes the schema).
    • Blast radius: every questions.json writer (round.py ops) and reader (surface/server.py,
      exporters.py); shared ops parsing. surface/ edited.

    Phase 2: question_shape.py (K6, K7, C1, C3, C4). Needs P2, P3.

    • Acceptance: surface/question_shape.py holds restates and withheld; round.py and
      shared/session.py call them and keep no other definition (grep shows no norm_alt/norm_text
      restates logic outside it); both servers ship withheld and alternatives[i].restates; a withheld
      shared text question has no rec card; surface/index.html reads the flags.
    • Tests: both Python suites (new units for both functions and the shared card rule); shared
      browser ui_claude_proposals.js, ui_discussion.js; 1:1 --part ui-c (ui_c.js covers folding),
      --part journey, --part main (ui_e.js covers withheld).
    • Blast radius: round.py add/reply/revise, session.py question input and _add_question,
      snapshot view, surface/index.html choicesOf/altsOf, exporters.py if it reads alternatives.

    Phase 3: served file and route (K9 id constant, K12, K13). Needs P5.

    • Acceptance: shared/web/question-shape.js and .css exist, served by both servers (STATIC
      entry; one surface/server.py route); composer, grow, fitViewport exist only there;
      shared/web/index.html and surface/index.html load them; the 1:1 answer and note boxes use the
      composer; the 1:1 page pins to the visual viewport.
    • Tests: both Python suites (shared/tests/test_server.py static list; surface/test_server.py
      new route and CSP); shared browser ui_composer.js, ui_keyboard.js, ui_phone.js,
      ui_askbox.js; 1:1 all three parts.
    • Blast radius: every composer( call in app.js (:1080,1090,1347,1376,1389,1390,1448, more
      below), core.js viewport consumers (core-viewport event), 1:1 answer box and keyboard handler.

    Phase 4: one renderer and basis (K8, K14, K17, C5). Needs P6.

    • Acceptance: one safe DOM markdown renderer in the served file; surface/index.html md/inline
      and app.js rich/inline/links removed; shared page shows basis as written, folded;
      REPO read from the server value.
    • Tests: both Python suites; shared ui_formats.js, ui_reflinks.js, ui_claude_proposals.js;
      1:1 all three parts.
    • Blast radius: every rendered text field on both pages (question text, context/facts, chat, notes,
      history, Claude replies). Highest visual risk; consider /testing:check-visual-parity baselines.

    Phase 5: docs (progressive disclosure, K2, K5). No owner choice beyond P1-P4.

    • Acceptance: question-shape.md states each rule once and points to SKILL.md Stance for Withheld
      and Basis; surface.md, lane-page.md, lane-shared.md point instead of restating
      (surface.md:93 short cap); written list of remaining page-specific differences (K15, K16, C12)
      with reasons, as feat(planning): bring the one-on-one interview page in line with the shared page #8633 acceptance asks.
    • Tests: tests/interview-defenses.test.sh, tests/reattach-slice.test.sh,
      tests/interview-surface-decision-mirror.test.sh.
    • Blast radius: model behavior in all three lanes; digest pins (SKILL.md untouched).

    Not covered by this design: #7303, #5795, #5893 (the other half of #8633's acceptance) and C12.
    Every PR here opens Refs: #8633 until those land.

    New product choices for the owner

    • P1 short cap: 80 (question-shape.md:23, schema, shared server) or 500 (surface.md:93,
      LINE_CAP). Recommend 80 for short only (it is the list label; one-line fields keep 500). Basis:
      judgment; unblocks Phase 1.
    • P2 Restates-the-recommendation: which definition (whole-word containment either way,
      round.py:262-280; or equality after folding, round.py:585-595) and refuse or warn, in both
      lanes. Recommend containment, refuse on write in both lanes, keep the page fold for old files via
      the server flag. Basis: judgment (containment catches more; refusing matches the reply/revise
      behavior the page lane already has). Unblocks Phase 2.
    • P3 Withheld shared question: keep 2-3 alternative cards (people vote among them, no
      recommended card) or take none (asked fully open). Recommend keep the alternatives. Basis:
      judgment (SKILL.md:189 bars a recommendation on a card, not alternatives). Unblocks Phase 2.
    • P4 Page alternative keys: restrict to a-d (old files with other keys fail) or keep any
      string on the page. Recommend restrict, after checking existing page fixtures for non a-d keys.
      Basis: judgment. Unblocks Phase 1.
    • P5 1:1 page keys under the shared composer: both already use Ctrl/Cmd+Enter
      (surface/index.html:2267) and keep single keys out of text boxes (:522). Choice: the
      composer's per-field send/escape replaces the page's document-level handler (:2263-2283) inside
      text boxes, or the page keeps its handler and the composer runs with no send key there. Recommend
      the composer inside text boxes, the page handler everywhere else. Basis: judgment. Unblocks Phase 3.
    • P6 One markdown dialect: union (headings, quotes, issue refs, mentions, bare links) or the
      shared page's smaller set. Recommend the union. Basis: judgment. Unblocks Phase 4.
    • P7 Question-screen layout on the 1:1 page (C12): in this effort as its own phase, or a
      separate issue. Recommend a separate phase after Phase 3, designed with the other lane. Basis:
      judgment; it is layout, not question-shape knowledge.
  6. kyle-sexton commented on Oct 22, 2026

    @kyle-sexton
    MemberAuthor

    State at the 2026-10-22 cutoff

    Shipped:

    Parked: Phase 3, #9197 (one served composer/viewport file for both pages); branch kept, resume steps on the PR.

    Not started:

    • Phase 4: one safe markdown renderer for both pages (union dialect, P6), basis shown as written, REPO read from the server.
    • Phase 5: docs progressive disclosure, so question-shape.md states each rule once and the lane docs point to it.

    Triage of #7303, #5795, #5893 (read-only, against main at aafe82d):

    The design record (P1-P7, phase acceptance criteria) is in the comment above.

  7. kyle-sexton commented on Oct 23, 2026

    @kyle-sexton
    MemberAuthor

    Update: Phase 3 landed (2026-10-22, supersedes the cutoff note above)

    Phase 3 shipped as #9242 (2f68361), which replaced #9197: one served question-shape file, so both pages use the same composer and visual-viewport fit. Two fixes landed with it:

    • the Notes key hint after a reconnect;
    • a macOS same-second race in test_tunnel.

    Still open here, not started:

    • Phase 4: one markdown renderer for both pages, basis shown as written, REPO read from the server.
    • Phase 5: docs progressive disclosure.
    • The post-Phase 4 fixes from the triage comment above.

    #8089 stays held until Phase 4.

  8. removed
    needs-humanHuman-in-the-loop required; autonomous sessions must not resolve items carrying this.
    on Oct 25, 2026
  9. kyle-sexton commented on Oct 25, 2026

    @kyle-sexton
    MemberAuthor

    Released for re-triage under the owner's 2026-10-24 rule: an issue stops for a person only for an intent or vision question, a security call, a host or attended run, or spend outside prepaid credit. The hold label came off and intake triage runs again now; it re-applies a hold, with a numbered question, when one of those applies.

    To hold this issue again, add needs-human (or status: needs-decision) and say why in a comment.

  10. added
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    priority: mediumReal value, no hard deadline; normal backlog flow.
    and removed
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 25, 2026
  11. 3 remaining items

  12. melodic-automation-lanes commented on Oct 25, 2026

    @melodic-automation-lanes
    Contributor

    Not admitted to the issue lane yet: Size large: the split into sub-issues at intake is pending (owner Q93).

  13. melodic-automation-lanes commented on Oct 25, 2026

    @melodic-automation-lanes
    Contributor

    The latest triage verdict holds nothing: the issue is at status: ready.

  14. melodic-automation-lanes commented on Oct 25, 2026

    @melodic-automation-lanes
    Contributor

    Refinement. A read-only run explored this repository, searched its issues and pull requests, and read the allowed docs to draft what follows. On an issue a listed human filed, it counts as the issue's spec once posted, while unedited; it is still model text, so check it.

    Intended outcome: Finish the remaining one-on-one alignment as separate changes: Phase 4 (one safe markdown renderer in question-shape.js for both pages, basis shown as written, REPO read from the server), Phase 5 (docs point to question-shape.md), then the #​7303 UI-9 label and re-measure fixes, with the page-specific differences written down.

    Dependencies

    • Phase 3 (#​9242) is landed: both pages already load question-shape.js (plugins/planning/surface/index.html:541).
    • #​8089 repo-path links wait on Phase 4 and on a decision about where a pinned commit SHA comes from.

    Related work

    Open questions

    1. Should this issue be split into one issue per remaining phase (Phase 4, Phase 5, post-Phase 4 fixes), each with its own checkable criteria, since the acceptance lines are not checkable and the work spans several changes?
      RECOMMENDED: Yes. Make Phase 4 the next lane issue, with Phase 5 and the #​7303 UI-9 and re-measure fixes after it, and keep #​8633 as the tracker. Basis: judgment
    2. Is the markdown dialect for Phase 4 settled as the union (headings, quotes, issue refs, mentions, bare links)?
      RECOMMENDED: Yes, the union. The 2026-10-22 state comment already calls it 'union dialect, P6'. Basis: #​8633 comment 2026-10-22 (design record P6)
    3. Where does the pinned commit SHA for #​8089 repo-path links come from?
      RECOMMENDED: Leave #​8089 out of this issue until the owner picks a SHA source, because no pinned commit reaches the page today. Basis: #​8633 comment 2026-10-22 (triage of #​7303, #​5795 and #​5893)
    4. Does the 'Acceptance' line about #​7303, #​5795 and #​5893 require every finding fixed, or may the out-of-scope ones (DX-3, DX-5, DX-9, DX-11, eval-first, UX-3, DX-7, #​5796 G4/G11) stay open on their own issues with a written reason?
      RECOMMENDED: Close them with a reason and leave them on their own issues. Basis: #​8633 comment 2026-10-22 (triage of #​7303, #​5795 and #​5893)

    Sources read

    • /home/runner/work/_temp/refine-data/context.json: the owner's comments from 2026-10-22 and 2026-10-23 give the design record P1-P7, say Phases 1-3 shipped (#​9160, #​9164, #​9242), and list Phase 4, Phase 5 and the post-Phase 4 fixes as open.
    • plugins/planning/surface/index.html:622: the page still has its own inline() and md() renderers.
    • plugins/planning/surface/index.html:541: the page already loads /question-shape.js.
    • plugins/planning/shared/web/app.js:542: the shared page still has its own inline(), links() and rich() renderers (app.js:551 and :607).
    • plugins/planning/surface/server.py:85: the 1:1 server already serves /question-shape.js.

    Automated refinement by the lanes App. Answer with a comment whose first line is **Decision recorded.**.

  15. kyle-sexton commented on Oct 26, 2026

    @kyle-sexton
    MemberAuthor

    Decision recorded. The owner answered in the Refinement session (2026-10-25), deciding the open items below on the facts:

    go with whatever the facts/data/metrics + /discovery:research says and ensure we're aligned with SOLID, DRY/SSOT principles

    I should only ever be in the loop ONLY when necessary (intent/vision changed, something came up during implementation that impacts trajectory/alignment, OR a high security risk) - I've covered this all before

    Question asked: Split the rest into Phase 4, Phase 5 and the post-Phase 4 fixes with the union markdown dialect, keeping #8633 as the tracker?

    1. Is the issue split into one issue per remaining phase (Phase 4, Phase 5, post-Phase 4 fixes), each with checkable criteria?
      Decided: Yes. Phase 4 is the next lane issue; Phase 5 and the planning: interview web view, deferred review findings #7303 UI-9 and re-measure fixes follow; feat(planning): bring the one-on-one interview page in line with the shared page #8633 stays the tracker. Basis: Phase 4 is not done on origin/main: plugins/planning/surface/index.html:633 and :655 keep their own inline and md, and plugins/planning/shared/web/app.js:542, :551 and :607 keep inline, links and rich; judgment for the split; kept.
    2. Is the Phase 4 markdown dialect the union (headings, quotes, issue refs, mentions, bare links)?
      Decided: Yes, the union. Basis: design record P6 in feat(planning): bring the one-on-one interview page in line with the shared page #8633 (comment) recommends it on judgment. No owner decision record answers P6, so this record decides it on the facts above.
    3. Where does the pinned commit SHA for fix(planning): link repo paths in interview recommendations to the pinned commit #8089 repo-path links come from?
      Decided: Out of this issue's scope: fix(planning): link repo paths in interview recommendations to the pinned commit #8089's SHA source is settled on fix(planning): link repo paths in interview recommendations to the pinned commit #8089, where its links are built. Basis: the 2026-10-22 state comment says no pinned commit reaches the page, so the work this issue tracks does not need one.
    4. Does the Acceptance line on planning: interview web view, deferred review findings #7303, fix(planning): interview page visual audit follow-ups to #5569 #5795 and fix(planning): interview page wrap-up friction: stale closed question, id count confusion, ops re-apply, restate cap #5893 require every finding fixed, or may out-of-scope findings stay open on their own issues with a written reason?
      Decided: Close each out-of-scope finding here with a written reason and leave it on its own issue. Basis: body Acceptance allows "closed with a reason"; kept.

    Acceptance criteria (converted from the body's Acceptance, wording unchanged except the dialect and split from items 1 and 2):

  16. melodic-automation-lanes commented on Oct 26, 2026

    @melodic-automation-lanes
    Contributor

    Split at intake (owner Q93). This issue is Size Large, so its done-when is split into 4 sub-issues, each holding its task-list lines as written.

    Automated split by the lanes App. Admission waits on this issue while a sub-issue is open; work-unblock closes it as completed once every sub-issue is closed by a merge or a listed human.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: mediumReal value, no hard deadline; normal backlog flow.status: readyTriaged, unblocked, and fully specified; eligible to pick up.work-class: structuralRefactors, migrations, contract changes; cross-cutting and hard to reverse.

    Fields

    No fields configured for Feature.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions