# Approved FedM8 clean design

Release-date update (owner direction, 2026-10-27): account sign-up and subscriptions open on Veterans Day, November 11, 2026 at midnight America/New_York (05:00 UTC). Launch week runs November 11–17. This supersedes prior November 1 launch scheduling, without changing prices, trial terms or the December 1 unused-invitation deletion date.

Reference: the owner-approved `clean-preview` shown October 15, 2026 (Contracts and Get Certified). The governing composition is the warm paper background, olive controls, left section rail, compact public discussion strip, and restrained page headings. Existing live data replaces the prototype's local examples.

## Product contract

- Primary sections: Chat, Veterans, Contracts, Grants, Get Certified, Learn (owner direction 2026-10-16 below: Chat first). Personal workspace: People & connections, Private chats, My Profile. Pursuit stages (the former Mission Board) live in Contracts > My pursuits and on My Profile.
- Section tabs hold related tools; More tools retains specialist tools and old route targets. Navigation remains normal hash navigation with browser Back support.
- Public scope controls: Discussions, NAICS rooms, Find teammates, Live All. Live All remains read only.
- A selected contract expands inside its result card. The same discussion root stays beneath its brief; independent +/− collapse preserves drafts, replies, acknowledgements and stream selection.
- General section chats use actual existing-room configuration: Community (`shop`) in Chat, Learning (`learn`) on Learn, Grants (`grants`) on Grants, Veterans (`veterans`) on Veterans, and Certification (`sam`) on Get Certified. A grant detail discussion uses `grant:<id>`; a lesson discussion uses `lesson:<slug>`. Specific item posting requirements remain in place. Each chat identifies its current destination and retains read-only Live All.
- Completed normal sign-in starts in Chat (`#/talk`), or returns to the Chat or Grants deep link the person signed in from (`next=os.html#/talk...` or `#/grants...`, email and Google/LinkedIn alike). Any other `next=` still starts in Chat. Restoring a session preserves the current deep link; recovery, email confirmation and identity linking retain their dedicated paths. (Owner direction 2026-10-16; this used to say sign-in starts at My Base.)
- My Profile opens the editable personal profile (`team-profile`); firm listing, firm library and Account stay reachable beside it. Parked tools remain excluded from promoted navigation.
- Certification uses one framed path with its view control, selected stage, task rows and opened tool. Back to tasks retains entries. Members and the checklist use compact disclosures in the same frame. All nine tools, Guided mode, the document packet and native saving/export handlers remain available. Short task-purpose descriptions stay visible so people can choose a tool.
- Official sources (2026-10-23, VETUX-026/008): a certification-guide screen (`assets/cert-guide-data.js`) or Get Certified walk-through step (`assets/flows/get-certified.js`) that was read against its official page carries `reviewed_on` and `source`, and shows one quiet line under the answers: "Checked against <page> on <Month D, YYYY>." with the page as a link (12.5px, `--ink-2`, centred on the stage). A screen whose facts come from more than one page lists the others in `also`, and the line names every page ("A, B and C"); a page that is not an https link drops the line. A step that was not confirmed shows no line; `reviewed_on` and `source` go together, on an allowed official domain (`qc/official-sources.spec.cjs`). A sole proprietor gets its own tax ID question in the walk-through (SSN or EIN, per the Federal Service Desk) instead of "Do you have an EIN?" (VETUX-007).
- Longer guidance belongs in contextual help dialogs. Use explicit Details controls beside resource actions. Keep facts, task purposes, current status, form labels, posting destinations, entitlement messages and safety acknowledgements visible where they affect an action.
- Learn opens with three featured lessons from the existing curriculum: free lessons on the veteran path (`veteran-certification-path`, `military-skills-to-naics`, `teaming-directory`; VETUX-022), never a paid lesson or an upgrade prompt. All lessons retains the complete native catalog and school filters; notes about the product itself (`phase: "platform"`) sit once under "Help with the product", a closed disclosure on every school tab, not in a school list, and a ? still opens them (its deep link opens the group). The public Free list ends with one hand-off, "Add your firm" then "Find work that fits"; every free lesson practises on a free route or public page. On Guides, the Bid Coach tile comes after the free tools and carries the neutral "Paid tool" mark, never a plan name. A lesson deep link opens its actual body and attached discussion. With names hidden, a lesson's cohort strip says "Names are not shown on this lesson." and shows only the counts the server returns.
- Private conversations use the existing participant-only RPCs. Sign-out or account change clears private conversation previews.
- No invented members, activity counts, earned coins, deadlines, scores or certification claims. Match-M8 remains the product name.
- After you publish (VETUX-016, 2026-10-23): My Firm shows a receipt (when, how many fields are shared and kept private, who sees it, how to edit or take it down) and one next step at a time from what the member already gave: finish the listing, register in SAM.gov (free; a paid third party is optional; hidden only when the SAM.gov record the member picked says Active, never for a typed UEI), apply for VetCert (SBA decides; hidden only for supporter and federal accounts, never for a typed certification or an onboarding box), add NAICS codes, find contracts for your code. Each step has Done and Not for me; Remind me later hides the steps until the first visit after 7 days. Choices live in the account (walkthrough_progress, flow firm-next-steps), or on this device when the account cannot save, and the page says which. A first visit with no draft shows only the wizard; with a draft the form comes first and the steps follow it. The receipt's Who sees it matches privacy.html (signed-in members; Directory, coins next to posts, members at your certification stage) and links there. No email, no price, no upgrade on this screen. Home keeps its one Level strip.
- Listing states and fact sources (VETUX-014, 2026-10-23): My Firm shows Draft · private, Published or Unlisted (no review step, so no In review; a row still marked review reads Draft · private), a note when the draft has changes members cannot see yet (it compares what members would see, so a private field the form fills from the account is not a change), the owner's listing history (published, updated, unlisted, following the Directory's own rule of published and listed; newest 50; other members cannot see it; in Download my data; Remove my directory listing clears it to one History cleared entry and, since the directory follow-ups (20261101140000), also clears the listing's contact email, phone and LinkedIn, which the Account screen says before and after the click; Unpublish listing keeps them), and where each detail comes from. Every fact is Self-reported unless the business name, UEI or CAGE code matches FedM8's saved copy of the SAM.gov record for the UEI the listing shares (`sam_entities`, written only by the worker), labelled with that copy's date and only for a shared field; a listing that keeps its UEI private gets no label, so nothing is worked out from a withheld identifier. Members see that label only while the server flag `directory_sam_labels` is on, and it ships off: UEIs and legal names are public, so a copycat listing could earn the label, and turning it on is an owner decision. While it is off, every card and the owner's step 4 preview read Self-reported (the owner is still told which details match). Boxes a SAM.gov lookup filled are still Self-reported (the draft keeps no tamper-proof record of where a box came from). Directory cards say the same, SAM.gov entity cards say when FedM8 saved its copy (and leave the Directory only while the Directory shows a FedM8 listing with the same UEI or CAGE code: published, listed and not a federal account's, the FedM8 branch's own test; so a draft, unlisted or removed copy of a real firm's identifiers, or a federal account's copy, no longer hides that firm's card; 20261101140000), a slow match reply never holds the Partners list, a federal account's published listing says the Directory never shows it, and nothing says verified, current or up to date. Veteran status is always self-reported.
- Certification plan (VETUX-009, 2026-10-23): certifications.html shows Your plan above the checklist: Ready now (one Next, then Can do at the same time), Waiting (Waiting on: <step>, or Waiting on <who> since <date>) and Done, from fixed prerequisites (structure before EIN and bank; all three before SAM.gov; SAM.gov before VetCert, WOSB, HUBZone and 8(a)). Four skippable questions (goal, what is done, SAM.gov status, a yes/no/not sure VA or DoD service-connected determination) are kept on this device and shape the plan: which steps are on it, Required, Needed first, Recommended or Optional with a one-line reason, and the VetCert card. Answers never change a step's status (review round 3: answers that wrote statuses could replace the member's marks from a stale or partial copy in another tab). Where they say steps are done or not done yet, the plan lists the steps the member has not marked with one button (Mark them Completed, Mark it I want this, or for Submitted / Started with SAM.gov unmarked or I want this, Mark it Waiting on someone else / Mark it In progress) that marks exactly those steps as the member's own, through the checklist's own save path and with one announcement; the button waits until the account copy has loaded (after a failed load it says to refresh) and any import or unsynced-changes choice is made. On the account it only fills a step that has no mark there (review round 4: insert, never update), so a mark made in another tab, on another device or by an import is kept, read back, shown and named in the announcement. A fill is never kept for "Retry unsynced changes" (that retry writes over the account): one the account refuses, or whose answer is lost, is read back and the page shows what the account has (no mark: said once and the button is offered again; when that read fails too, the steps say the page could not confirm them, with a line to refresh, and the button waits); one never answered shows the account's copy on the next load (review rounds 6 and 7). A step with an unsynced change of the member's counts as marked, and a press replaces an unsynced clear of a step it fills, so a retry never deletes what the press marked (review rounds 5 and 6). A kept mark the page could not read shows as marked on the account, with a line to refresh. A step's own In progress, Waiting or Not started clicked while a press's fill of it is on its way saves I want this as the member's own click, so the fill's outcome never undoes it (review round 7). While the account copy kept by an ignored fill is being read back, the save line says Checking your account progress; it reports success only after reconciliation. If a guest import saves the account checklist but cannot save this device's plan answers or dates, the page names that partial result and keeps the import choice and source for retry. After a press, focus moves to a heading, never to another button that writes, and a double click counts once. When an answer and the member's own mark disagree, or the plan waits on a step marked Not for me, a Check this note says so and opens the step; the mark is not changed. In progress and Waiting on someone else are set by the member, stored as planned on the account, and keep their date on this device. Signed-in plan reads and unrelated edits preserve other tabs' newer details, even when this tab's checklist is stale. The private determination answer stays neutral until the current sign-in scope is known; failed auth keeps that answer hidden. The determination answer stays on this device only (an account's copy is cleared at sign-out; a signed-out copy is removed when an account signs in on this page or by Clear my answer, and other open tabs stop showing it), its inputs opt out of browser form restore, it changes only the VetCert card (SDVOSB, VOSB, or both, with SBA Certifications and VA.gov), and it is never sent anywhere. The next-card button stays the one primary action.

## Owner direction 2026-10-16: Chat leads

Chat leads. Search feeds the rooms. Where this file or `DESIGN_DNA.md` puts search or My Base first, the owner's 2026-10-16 direction wins: Chat comes first and members land in it. Everything else in this contract still holds: no invented members, counts, coins or claims; privacy; Live All read-only; drafts preserved; auth gates.

- One menu order: `NAV_ORDER` in `assets/approved-design.js` is the only source. The rail, the phone dock and the bundle's legacy rail (`os-boot.js` SPACES, through `window.FedM8NavOrder`) follow it; `site-social.js` relabels and never re-sorts. Order: Chat, Veterans, Contracts, Grants, Get Certified, Learn (Get Certified sits above Learn, as the legacy rail always had it; certification is a day-one question). The phone dock shows all six (Get Certified reads "Certify" there, with the full name as its label). Find Work, Grants, Get Certified and Veterans stay one tap away.
- The public site lists Contract Chat first in its top bar, and the homepage leads with the Contract Chat pillar.
- Chat home (`#/talk`, `assets/chat-home.js`) is calm, in three parts: left "My rooms" (Everything, the general rooms, your NAICS code rooms, conversations you follow, Messages) with the current one marked; center one "Ask your people" box that names where it will post, then one stream of new posts from your rooms with "Unanswered near you" mixed in; right one card at a time (best contract for you, who's around, wins and milestones). The hero, Mission Board, coin case and the second Top M8 are gone from Chat; coins stay on My Profile. Counts are real (posts in the last 24 hours, from `my_rooms_feed`) and are left out rather than guessed when that read is not available.
- A member with no Team Up profile types and presses Post like anyone else. The first time, a short "Before your first post" card opens under the box (owner direction 2026-10-16, r05; `assets/first-post.js`): how your name shows (first name and last initial, or the company name), post as Me or My company, Sub or Both for a company (Prime only with a SAM-verified UEI, so it is shown but not offered), the codes from sign-up, and the self-reported Veteran tag for veteran accounts only. Post again saves a real, active Team Up profile through `commons_save_profile` and posts; the words stay in the box if anything fails. The full card is offered afterwards ("Finish your card so primes can find you"). A paused or held profile keeps its own message and next step. The same card sits under the private-chat gate.

- Names: "Contract Chat" is the public name; inside the app the section is "Chat"; any conversation is a "room"; the helpful mark is a "Helpful" button with its M8 count.
- Words: chat screens read one shared table, `assets/chat-words.js`. Server reason codes become plain words and one next step; raw codes are never shown.
- Rooms (owner direction 2026-10-16, r04/r07/r12): topic rooms are real pages again. `#/talk?room=<id>` opens the room and `&thread=<id>` its thread; Chat's My rooms lists General, New here, Veterans Hall, Supporters, Getting certified, First bid, Running the shop, Learning and Grants. General (`general`, new) is the room for anything and Chat's default room when a member has no code; `shop` reads Running the shop again (this replaces "Community (`shop`) in Chat" above); `sam` reads Getting certified; `veterans` reads Veterans Hall. Veterans Hall keeps veteran-only posting (supporters read and post in Supporters), the not-a-claim-file note with the accredited-representative search and the 988 line, Who helped you, and four standing threads that a member's first post starts (never seeded posts). New here holds hellos: a ready-made hello on Start and in the room, and Help a newcomer lists real hellos with no reply. No automated greetings. A question posted from Ask lands on its thread or conversation with "Posted in ..." once.
- Talking is free (owner direction 2026-10-16, r06): reading and talking is free for every member, and paid plans add data depth and outreach. Every plan sees member names (first name and last initial, or the company name), badges, coins and the profile link in every room, Live All, Top M8 and Help a newcomer; contract and grant conversations open on Free (title, agency, due date, SAM link; summaries, fit and saved details stay paid). Tapping a name opens the lean member card (name, teaming role, badges, coins, Message) on every plan; the full card stays on Basic. New posts and replies have separate daily limits: Free 3 and 20, Basic and Pro 10 and 50, first-week accounts 3 and 10. The acknowledgment is asked once per account for NAICS code rooms and once per conversation elsewhere. Who's in rosters, Reach out, Build my team, award and directory conversations keep their plans. This replaces "names are Basic and up" wherever an older note says it. Privacy is unchanged: only active (published) profiles, no emails, phones, user ids or UEIs.
- Honest states: no browser-only discussion and no sample people. When chat cannot load, one line says so, Try again retries, and the unsent draft stays in the box (kept in this tab) marked "Not sent yet".
- One room (owner direction 2026-10-16, r03): every conversation is drawn the same way by `assets/fedm8-room.js` (`FedM8Room`): contract, grant, award, lesson and NAICS code conversations (`#/talk?item=`), Who's in Talk, and the actions, menu and composer pieces of the contract room, the section panels and the classic room pages. Tabs read This contract (or This grant, This code...) | NAICS code | Live All; Live All stays read only and says where to post instead. A pinned FedM8 AI note leads a contract when it has one. Replies nest eight levels with collapse kept in this tab. Every post has the same actions: Helpful (one label, one RPC), Reply, and a "⋯" menu with Report, Hide this person and Remove mine (a popover on a wide screen, a bottom sheet on a phone). The rules line sits above every box. Classic rooms keep their vote arrows.
- Safe everywhere (owner direction 2026-10-16, r17): a heads-up under the box while typing runs the server's own rules (`talk_check_draft`); a refused post shows the server's reason with Edit and Why, and the words stay in the box. Rules fit the room: veterans can talk about a DD-214 or a disability rating; Social Security numbers, VA file or claim numbers and pasted record text stay out everywhere; grant rooms may restate the public grant's figures; an hourly dollar rate is pricing in every other room. Hide this person covers public talk and private messages, and My Profile lists "People you hid" with Show again. Members start at most 20 new private conversations a day (5 in the first week). The admin report queue shows reported private messages and room posts with their words, how many wait and the oldest against a 4-business-hour target.
- Grants get the same chat (owner direction 2026-10-16, r02): a grant page reads like a contract page. One row of doors sits under the facts: "Talk about this grant · N" (the main button; it opens the grant's conversation below and puts the cursor in its box, or signs in and returns to the grant), "Find a partner" (Who's in for `grant:<id>`) and Watch. The conversation keeps the approved inline panel and reads This grant | NAICS code (guessed) | Live All; Grants.gov lists no NAICS code, so the code is guessed from the grant's words and every place that shows it says so. A pinned FedM8 AI note leads (written by the worker after the summary pass from the summary's first sentence and the public Grants.gov fields, keyed `grant:<id>`, never with member credits; members read it on every plan). The grant rules line replaces the contract one: talk about what the public grant says, keep your own budget and rates out, questions go to the agency contact on Grants.gov. Grant cards show "Talk · N" and "N in". NAICS code rooms list grants that may fit, marked "code guessed from grant text", opening the grant's conversation and page, never SAM. Ask on a grant page posts in "this grant's conversation".
- Talk doors (owner direction 2026-10-16, r14): one small "Talk · N" chip opens the room for a search hit (notices and grants), a NAICS lookup row (find-contracts.html, mos.html), a grant card and a Find Work tile. Each page makes one count read (`talk_door_counts`, open signed out; the newest member post previews only for members). Signed out, the chip signs in first and then opens the room. Counts are real post counts; a tile's old count of the single AI note is gone. A set-aside notice (SDVOSB, VOSB, WOSB, EDWOSB, HUBZone, 8(a)) says so in its contract room with "Ask in Getting certified", and Ask offers the same room; nothing says any firm is certified.
- Honest about live (owner direction 2026-10-16, r19): nothing says "live" unless it updates itself. Chat surfaces have no live dot; "Who's around" keeps its dot because it reads a real heartbeat. While a room is open and the browser tab is visible, a "N new replies · Show" pill appears when someone posts (`talk_pulse`, every 30 seconds); it never moves the page and pauses while the tab is hidden. In the contract room that pill replaces the Refresh button; Refresh comes back only on a server that does not have `talk_pulse` yet (FIX-1 wording fix, 2026-10-17). An open private chat checks for a new message every 10 seconds while visible.

- Open doors (owner direction 2026-10-16, r09): signed-out visitors can read real talk. forum.html leads with "Recent posts in Contract Chat" (with a NAICS code picker; the read goes back up to 60 days, so headings say "Recent", never "Happening now"), vets.html shows what members ask in Getting certified plus a Veterans Hall member count, and each NAICS lookup row (mos.html, find-contracts.html, partners.html) has "Recent talk". One anon read, `public_talk_preview`, returns at most three posts from open rooms only (NAICS code rooms, General, Getting certified, First bid, Running the shop, Learning, Grants), each over an hour old, with no open report, by nobody on hold, that passes the safety check again at read time. Authors show as a role ("A member · Sub · Veteran (self-reported)") unless they turned on "Show my public name" on My Profile; no ids of any kind. Veterans Hall, Supporters, New here, private messages, contract and grant conversations never show words; Veterans Hall gives a member count only. Counts below 3 are left out. A code preview may carry the labeled FedM8 AI summary of an open contract and this week's FedM8 AI weekly note. "Join this conversation" signs in (or opens sign-up), then the room. The block is `data-nosnippet` and stays out of the page when the read is not there. privacy.html and terms.html say so in plain words.
- Launch day (owner direction 2026-10-16, r08): warmth comes from real, labeled people and labeled FedM8 notes, never made-up members or seeded posts. "Founding crew" and "Staff" are server-set labels (`community_crew`, admins read as Staff), shown as a small pill on posts and in badges; nobody can give themselves one. A per-email `signup_allowlist` (service role only) lets invited founding members open accounts before November 11 and sets their label; no global flag changes, and the owner adds the real emails. Launch week shows one topic a day (Nov 11-17) in the Chat home rail, on each room page for its day and on forum.html; it names topics and rooms, never people or counts. NAICS rooms carry a pinned "FedM8 AI · Weekly note" from `room_weekly_notes` when one exists for this week (public contract counts only; the store and the display are in place, and the worker job that writes the note comes with the weekly room rhythm, r16).
- Follow and hear back (owner direction 2026-10-16, r10): every room, code room, lesson, grant and contract conversation has a Follow / Following toggle with "We'll tell you when someone answers.", and every thread (a top post, a classic room thread) has its own. Posting in a thread, saving a notice, watching a grant and joining a list follow it for you; an Unfollow is kept. The Inbox opens on every plan with Replies | Messages | All | Unread (saved searches stay Basic, so a Free Inbox holds replies and messages and lands on Replies). Replies name the room ("A member replied to you in NAICS 561720 · Janitorial services"); new posts where you follow come as one alert per room per hour; opening a room clears its alerts; nobody hears about their own post or someone they hid. "Email me replies" sits in the Inbox: Right away (at most one email an hour), Once a day (the default) or Off, plus a weekly "Your rooms this week" email on every plan; both live with the other email switches (`notification_prefs`, `set_team_prefs`). Emails name the room and link to it, never quote the post, and carry one-click Unfollow and Turn off links (a link opens a page with one button; nothing changes on open). The worker job is built and tested but off until the owner turns it on (`SCAN_RUN_TALK_MAIL`). Chat home's left list reads "My conversations": what you follow plus your latest private chats with an unread dot. Member, profile, directory and award conversations are not followable.
- Open doors follow-ups (owner direction 2026-10-16, WP7 verifier fixes): the public preview answers from a five-minute snapshot that any removal, report, hold or name change clears at once; a section label hides with the preview; every card's link says where it goes; before the server has the read, the NAICS lookup leaves out "Recent talk" (no empty box, no repeated calls). An invitation is taken only by a confirmed address, then deleted; unused invitations are deleted on December 1, 2026. Launch week's "Your NAICS room" opens the member's first code room.
- Certification rooms (owner direction 2026-10-16, r13): Getting certified has a room per program and per step (`cert:<track>` and `cert:<track>:<phase>`: SAM.gov, Small business, VetCert, WOSB, HUBZone, 8(a) × Check, Gather, Apply, After), listed under Getting certified as "Rooms by program" (each program room links to its steps; WP9 verifier fix, 2026-10-17). The public guides (cert-guide.html) carry one quiet line per step, "Stuck here? Ask people on this step · N posts", that opens the room (reading and posting ask you to sign in); the count is posts, never people, and guide progress stays in the browser. Get Certified stages, the cert desk router and set-aside notes ("Ask in the VetCert room") open the program rooms. Each room pins the guide's rule: "SBA decides eligibility. Share what happened to you, not a ruling. Do not say you are certified until SBA's approval letter arrives." Posting is post_talk with its gates; one acknowledgment covers every certification room ("I won't say I'm certified before SBA approves it, and I won't post anyone's records."). In these rooms a certification shows only as a "SAM lists SDVOSB" chip from SAM data for a verified UEI; typed or directory certifications never show there. "I'm working this step" is for directory-listed members, and a step shows a people count only at 5 or more. When SAM starts listing a program for a verified company, one quiet line shows in that program's room (directory-listed members only); no pop-up, never from a checklist tick.
- Weekly room rhythm (owner direction 2026-10-16, r16): rooms carry pinned host cards labeled "FedM8 AI · not a member" (or "FedM8 team" for staff-hosted office hours), never a person and never "Jev": Monday "Last 7 days in 541512: …" (the count covers the seven days before Monday; WP9 verifier fix) with links and sources (SAM.gov, Grants.gov, agency forecasts) and the time it was built, from a plain template; Tuesday how many questions still wait for an answer (a count, never a quote, with a "Waiting on an answer" tag on the post); Wednesday office hours scheduled by staff (`schedule_office_hours`); Friday an opt-in "Share your own win or lesson" prompt in General, Veterans Hall, Getting certified, the six certification program rooms (no award line) and every code room (with public USAspending award totals for the code), never private pipeline data; grant rooms get no weekly cards (each carries its pinned FedM8 AI note and closes on its own date); one batched "New today" line a day per code room; and "Catch up" on a thread past 15 replies (a model summary only when ai_enabled is on and both the injection screen and the citation check pass, labeled "checked against the replies and the notice title"; otherwise the reply members marked most helpful and the official link, or nothing). A small strip names only the days this room has a card, with today marked. Members read the cards through the room's own gate (`room_host_notes`); the Monday note of a code room also feeds the public preview's weekly note. The worker job (`worker/room-rhythm.js`) is built and tested but off until the owner sets `SCAN_RUN_ROOM_RHYTHM=true`.
- Teaming grows out of talk (owner direction 2026-10-16, r15): a new post in a contract, grant or NAICS code room can say what it is "Looking for": Need a sub, Can sub, Need a prime or 1099 (grants: Lead applicant or Partner). Tags are roles only, never a price or whether you will bid; the post goes through post_talk's rules (`post_talk_tagged`), and on a contract or grant one box adds you to Who's in with the matching role in the same step (its SAM, UEI and set-aside checks still apply; a blocked join leaves the post standing and says why). A tagged post shows a soft olive tag ("Needs a sub"), and other members tap "I'm interested · N"; the poster gets one Inbox note per post with a count and sees who (`my_post_interest`), each with "Open chat", which opens the existing private chat with a first line filled in that they can change (the first-message acknowledgment and the daily cap of 20 new chats, 5 in the first week, stay; "New chats today: N of 20" shows on a new chat). One join control: "I'm in as Prime / Sub / 1099" (grants: Lead applicant / Partner / 1099) opens the Team Up join on that role, which asks what other members can see first and then joins; the old "Raise my hand" (which always failed) and the role picker that only stored a role are gone. Team rooms stay Pro and contracts only, and say so; a team room lists the NDA, teaming agreement and letter of intent, with the pinned line "Prices and rates belong here, after a signed agreement. Start with the NDA." partners.html describes Chat, not emailed notes, and no longer says "Jev".
- Who's here (owner direction 2026-10-16, r18): the top of every contract, grant and NAICS code room has one line from real reads (`room_people`): "3 raised a hand · no sub yet · 1 online now" (grants: "no partner yet" / "no lead applicant yet"), or "12 members work in 238220 · 2 online now". Online now is a presence heartbeat in the last two minutes among those people; FedM8 never records or shows who is viewing a notice. Under it, "People to say hi to": up to three members, each with one plain reason from real profile fields (raised a hand as a sub, the role still missing here; same code; same state; same skills; never a certification, never a score) and "Say hi", which opens the private chat with an editable first line. Only members listed in the directory with an active Team Up card who keep "Suggest me" on (My Profile), never someone either person hid, never a government account. On a contract or grant, names follow Who's in (Basic and up; Free sees the counts and "Names show on Basic."); a NAICS code room shows them on every plan. Hide closes the card for that room in this browser. On a phone the people become one row you can swipe. `naics_member_counts` is open signed out and leaves out counts below 3.
- Follow follow-ups (2026-10-17, WP8 verifier fixes): members can change only read_at on their own alerts; the reply email reads the room's name, link and author from the server (`talk_mail_alerts`) and mails sign-in addresses only (`talk_mail_recipients`), never the editable profile email, and sends nothing it cannot verify; one post gives one alert after ten minutes too; a thread follow needs a conversation you can follow, a notice or a grant FedM8 has; email claims are kept 35 days. Reply emails stay off until the owner turns them on, and plans.html and the Inbox say "start soon". The nonpublic check also reads "I G E", "gov estimate", an officer who texted, emailed, messaged, called or wrote a figure, and an officer passing on who wins, the award or the incumbent.
- WP6 follow-ups (2026-10-17): the pinned FedM8 AI note is read one conversation at a time (`talk_pinned_note`); there is no table-wide read. The grant page's conversation shows each post's replies ("1 reply") and links "Open the full conversation"; one rules line per tab (the grant's rules on This grant, room rules on the code tab) and the note under it follows the tab; its count reads again after your own post; the grant page has "Ask about this grant". Grant rooms ask "I'm not working on this grant for the government" and refuse "nonpublic information about this grant". The nonpublic check needs a figure or a buy detail, so "The RFP is not public yet, anyone know when it posts?" is fine. A Free member's Grant summary leaves out what Basic adds instead of "Not listed". Who's in reads "2 in · 1 prime".
- WP5/WP6 follow-ups (2026-10-17): the rules line sits above the box in every composer, the Chat home Ask box included; a refused post shows only the refusal (the heads-up clears); Chat home posts and NAICS code previews have the shared actions and "⋯" menu; a menu item whose server function is missing stays out after one side-effect-free check; the "new posts" pill waits until its room is on the page, and Refresh comes back where `talk_pulse` is missing.

- WP9 follow-ups (2026-10-17): a signed-out visitor who taps a guide door or any conversation link (`#/talk?item=...`) gets the sign-in dialog and lands back in that conversation (`next=`). Get Certified gives every stage tab its own "Stuck here? Ask people on this step" door, and "Rooms by program" stays in sight in the path's footer. The record check also refuses a nine-digit service number, SN, DoD ID or EDIPI (from 1969 to 2011 the service number was the SSN) and an EIN or TIN with its number; "2500 flat", "2500 each" and a bare figure in a post about price count as a price, while counts and labelled numbers ("building 5100", "SF 1449") never do. "Waiting on an answer" leaves a question once someone else answers it, and staff office hours cards pass the same room check (no phone numbers, rates or "Jev"). "Open the guide at this step" opens that step; a program room's tab reads "This room"; the forms hint is not repeated under a certification room's rules line.
- Reward the people who answer (owner direction 2026-10-16, x04): the asker marks one reply "This answered it" (only the asker sees the button; never their own reply; classic rooms too). The thread shows "Answered" as a word with a check, and the reply says "This answered it · marked by Dana R.". Accepted answers are counted apart from M8: the leaderboard rule stays one M8 per Helpful mark from another member, so an accept adds no M8 and the HELPER coin keeps its counter. Two coins come from what happens in the rooms, never claimed: ANSWERED (5 different askers marked your reply, never your own questions or your company's) and WELCOMER (the first reply to 3 newcomers' first posts, marked Helpful by the newcomer). Self-votes earn nothing. My Profile shows answers that worked and newcomers welcomed with each coin's progress, and every member card shows Helpful marks, answers that worked and newcomers welcomed. A code room and a classic room name their top three "Go-to helpers in ..." with View rankings; that line replaces the second Top M8 board. "Unanswered near you" means no answer was marked: a question with one or two replies and no marked answer still waits. One label everywhere: "Helpful · M8 N" (the contract room's "Score N" is gone).
- Check the record (owner direction 2026-10-16, x03): under a question in a contract or grant conversation, "Check the record" quotes up to three short lines from that notice's official record, each with where it came from and a link: the Q&A and the notice's changes on Basic, short snippets from the text inside the notice's files on Pro (the raw text never leaves the database), and the public grant synopsis on every plan. It is a plain search, no AI, so it works while credits are paused; it never guesses and leaves out any line with a dollar figure. With no match it says "Not in the record yet. A member may know, or ask the contracting officer in writing before the question deadline." and what it searched. The asker can share one line into the thread; the server finds the words again, posts them through the normal post checks and adds the "From the record" tag, so the tag only sits on a real quote.
- Keep talking after the deadline (owner direction 2026-10-16, x02): a contract closed at its response deadline says "Talk closed at the response deadline (Nov 6). What happened next:" with "Lessons from recent awards in 561720" (the NAICS room) and, once the award shows on USAspending, "Likely award: Acme Facility Services LLC · N people in the award room" and Open. The match is the solicitation number plus the agency, never titles; until then it says "The award room opens when the award shows on USAspending. DoD awards can take about 90 days." The solicitation thread stays locked. Award rooms read on every plan, like the contract talk they continue (FIX-1, 2026-10-17: the x02 recommendation asked for the same tier as contract talk, and since r06 contract talk is on every plan; `commons_context`, `award_room_info` and `notice_award_link` now agree with `talk_for_item` and `post_talk`, which already let every plan read and post). Award Intel's prices and winner patterns stay Pro. The owner can still choose a paid tier for award rooms; until then this is the one tier everywhere. A plan line is never a dead end: the page keeps its phone header, the way back and the room's name. An award room pins "Working on this award? Say what help you need." and its rules line ("Share what you learned. No prices, no other bidders' details, nothing marked source selection."). The awardee can claim the room only with a UEI-verified company card whose UEI matches the award; then it reads "Claimed by ... (UEI verified)" and that company's posts carry "Awardee". Award Intel's "Find subcontractors" opens Who's in for the award, which links to the award room page.
- A chat shell built for the phone (owner direction 2026-10-16, x01; it builds on the approved six-section phone dock above, Chat first, rather than a four-tab bar): a room fills the phone screen. The page title, public filters, topic photo and Ask bar step aside; a header row holds Back, the room's name and "i", which opens Room info (contract details, Team up, View team, related codes, a certification step's opt-in) as a bottom sheet. The box is pinned above the dock (fixed, with safe-area padding, and the page leaves room to scroll the last post clear): one line (rules, box, a 44px Post) that opens to its full form while you write; unsent words stay in this tab. The code search opens as a bottom sheet with 44px rows. The coin case is gone from Chat's room, code and board pages (coins stay on My Profile). The floating "Chat — this contract" button is gone on phones, the contract room's phone dock has 44px targets, and "Send feedback" moves under My Profile on phones. The homepage's four facts fold into one "Facts you can check" line on a phone (same words, same regulated-claim tag). Glossary terms in step lists no longer break onto their own lines.

- FIX-1 follow-ups (2026-10-17): Who's here counts only hands a member raised or confirmed; a Match-M8 add the member never confirmed reads "N matched by Match-M8, not confirmed" and is never suggested or called a raised hand; a Say hi reason never repeats a certification word a member typed as a skill. "I'm interested" keeps its history: taking it back never resets the 30-a-day cap, and only a member's first tap on a post alerts the poster. A poster can invite an interested member or a suggested person to their team room (Pro, contracts; everyone else sees the plain Pro line); every member follows up in a private chat ("Open chat"), and no copy points to Pro email. The answerer gets an Inbox note when a reply is marked "This answered it" (contract-room discussions included). Check the record never quotes a money figure (USD, rates per hour, "dollars"). On a phone, only focus in the message form opens the pinned box, leaving it always folds it to one line ("Not sent yet" stays while it holds words), classic room threads get the same header and pinned box, and Send feedback lives on My Profile for every plan. My Profile shows the coin case and progress toward HELPER, ANSWERED and WELCOMER on every plan; a certification a member reports themselves shows as an outline coin labeled "self-reported", never "Certified". Community Q&A (support page) posts through the same room check with a daily cap and a member Report; a trusted host's report (HELPER coin, 30 days, no upheld report) counts as three. Greeters (r12): members with 30 days and no upheld report opt in on My Profile and staff approve them (staff at once); an approved greeter's posts show "Greeter", and the worker (`SCAN_RUN_GREETER_NUDGE`, off until the owner turns it on) leaves one Inbox note for up to two greeters when a New here hello waits two hours. Help a newcomer puts first, marked "Close to your work", up to three hellos whose authors fit you (your own stored people fit, the score People already shows you); without a fit row nothing is suggested. FedM8 never posts a welcome for anyone.

- FIX-2 follow-ups (2026-10-17, final verification fixes): the approved design is light-only, also when a device asks for dark mode. The legacy chat shell's dark tokens apply only outside the approved shell (`body:not(.fd-design)`); inside it the chat tokens map to the paper/olive `--fd` tokens, so Chat home, every room and the NAICS code feed keep dark green ink on paper (the harness proves it: `--color-scheme dark` with `assertContrast`, `_internal/qa-harness/examples/dark-contrast.json`). On desktop, "Send feedback" sits at the foot of the left column instead of floating over the right rails; on a phone it stays on My Profile. A conversation opens with its title near the top: the section photograph is a short banner there and the generic Ask bar stays out (the room has its own box). A conversation that is gone gets a real page (header, Back, title, the reason, one next step). Classic room lists on a phone get the same shell as a thread (header row, room chips tucked away, "Start a thread" pinned and folded). Veterans Hall leads vets.html (its heading is the page h1, Join Veterans Hall is the first action); the MOS lookup says "N veterans on FedM8 work in CODE · Join Veterans Hall" (`naics_veteran_counts`, 3 or more only) and Veterans Hall says how many other veterans are on FedM8 now (`veterans_here_now`, a count only). The pricing heads-up is plan-neutral ("Share prices only privately with teammates, under a signed teaming agreement"; team rooms are Pro). Deferred, recorded here: the r08 welcome email that names the member's room and code count. It needs the waitlist to store a NAICS code (new `waitlist` columns accepted by `save_release_waitlist`, with privacy-inventory rows) and a one-time Railway send job; it is built with the Nov 11 email, not before. Open owner decision: the homepage hero line ("Get certified. Win contracts. Find your crew.") is the approved Day-1 line pinned by `qc/lead-notify`; it changes only when the owner approves new words.

- FIX-3 follow-ups (2026-10-17, final recheck fixes): every room is one component. The contract page's own discussion and its related NAICS / Live All rail are drawn by `FedM8Room.mount` (assets/fedm8-room.js), the same room as every `#/talk?item=` conversation: threaded replies eight levels deep with collapse kept in this tab, Helpful · Reply · Follow · ⋯ on every post, the pinned FedM8 AI note, the rules line above the box, the acknowledgment, Looking for, the heads-up, the server's refusal with the words kept, the "new replies" pill, Check the record and This answered it. A reply from the rail goes to the post's own conversation under that conversation's rules and acknowledgment, and Live All stays read only. Contract Room X keeps the frame: the title row with ? and +/−, the set-aside note, Who's here, the place right under the brief, parking while the search list redraws (a reply that lands meanwhile still paints), the code picker, one view per code and the scope events. The classic rooms (talk_threads) draw on the same mount (`stream: "classic"`): the thread list, each thread, Start a thread and the reply box, with their vote arrows; the room page keeps its frame (room list, intro, Follow, the Veterans Hall cards, the hello box, standing threads, the phone header). The PR #621 renderer in Contract Room X stays only for a page where the component did not load. The section panels under each section page (Veterans, Learn, Grants, Get Certified) remain the compact panel built from the same pieces (actions, heads-up, refusal, pill); they preview a room and link into it. Also: the join control's selected role is readable wherever it sits (Tools bar included); a New here hello is neither listed nor opened for a member its author hid; Check the record also drops "2.1MM", "2.5 M" with a value word, "two million", "1 200 000" and bid or quote figures; Veterans on FedM8 now counts only active Team Up cards marked veteran (the badge rule), read once a minute; the MOS lookup reads its veteran counts once the list settles; Veterans Hall's crisis links are 44px on a phone; the contract page's Pro teaser keeps its dark ink in system dark mode; support.html says "You post as Sam S." and "Using FedM8 tools". The r08 welcome email is built (worker/welcome-mail.js, a dry run in worker/run-welcome-dry.js): it names the member's NAICS code room (General when the row has no code) and, at 5 or more, how many other people in that code joined the list, never who. Nothing sends it and nothing schedules it. Owner steps remain: the waitlist asking for a code (new waitlist columns accepted by `save_release_waitlist`, with privacy-inventory rows), the send job and its timing, and the founding-crew allowlist emails. Open owner decision, unchanged: the homepage hero line ("Get certified. Win contracts. Find your crew.") is owner-approved copy and stays verbatim until the owner picks new words (qc/lead-notify pins it).

- FIX-4 follow-ups (2026-10-17, final verification round 4): one word for publishing in an open room, **Post** ("Post reply" in a reply box), on Chat home, every room, the contract room, the section panels and the classic rooms; a private chat still says Send. The section panels (Grants, Learn, Veterans, Get Certified, My Base) keep the compact panel, now with the room's pieces too: Follow on every top post of a conversation tab, replies nested under their post (open, as in the room) and the pinned note in the room's words ("FedM8 AI · Pinned · AI brief"); Reply and the header link still open the full conversation. A reply, an answer or a private message in the Inbox is shown as plain text, never as a link or formatting someone typed; alerts FedM8 writes keep their formatting. The Inbox reads its email switches once (a read-only call) and its count names the open box ("No unread replies · 2 unread in All"). A contract closed at its deadline shows "What happened next" on the contract page as on the conversation page, even when the search list redraws while it loads. On a phone, the contract room keeps each post's avatar beside the name (only the source chip takes its own line), "See Basic", source chips and every crisis link are 44px tap targets, and the record sheet's radios are olive. The Pro teaser's "See Pro" is white on olive. Live All and Chat home leave out a New here hello its author hid from you, and opening one by link says "This hello is not open to you." Open-room checks read pasted look-alikes (en dashes, zero-width marks, fullwidth and other-script digits, "l23", "five55") the way a person does. Check the record also drops "1.2B", "2.5 m" or "2.5 K" near a value word and "mln". plans.html names award rooms on Free (they open on every plan) and Pro keeps directory chat. support.html calls the app FedM8, not Workspace. The welcome email (still not sent by anything) carries FedM8's postal address and a one-click "Leave the list" link that keeps only a hash of the address.
- FIX-5 follow-ups (2026-10-17, final verification round 5): the "new posts" pill never counts a New here hello, or the replies under it, that its author hid from you, so it never promises posts that do not show. A thread that will not open for you (a hidden hello, a thread by someone you hid, or one that is gone) says what failed, drops its Follow button and gives a real way on ("Open New here" or "Back to <room>"); a connection failure keeps Follow and offers Try again. A contract link (`#/opportunities?notice=`) for a notice that is not in the current results (a contract closed at its deadline) opens that notice at the top of the list, with "What happened next", and keeps it when the list redraws; when the notice cannot be read at all, the list says so and offers its conversation instead of quietly showing a different notice. Open-room checks also read a phone number written with any one separator mark ("555/123/4567", "555 - 123 - 4567"), spaced single digits, every dash look-alike and every script's digits, and an address written "joe(at)example.com" or "joe@ example.com"; dates, NAICS codes, notice numbers and counts still post. Check the record also drops "900 thousand", "2.5 millions", "1.2 trillion", "3 grand" and "2.500.000", and keeps a length next to a value word ("3 m of fencing", "2 m wide"). On a phone the NAICS lookup's sector chips and its row links are 44px tap targets.
- FIX-6 follow-ups (2026-10-17, final verification round 6): open-room checks stop refusing ordinary posts that FIX-5 started refusing and catch the contact forms that still got through. An "@" with a space on both sides is an address only when the word before it looks like a mailbox ("joe.smith @ gmail.com"), so "Get your UEI @ sam.gov first." and "Thanks @ ana.lee for the tip" post; "joe@ example.com", "joe(@)gmail.com", "joe [@] gmail.com" and "joe.smith@army .mil" are refused. A list of round numbers or of numbers before a unit or count word ("250/500/1000 gallons", "100/200/1000 count") is a list, not a phone number, unless the post says call, text, phone or number; a phone number written with separator runs ("555--123--4567", "555 //123// 4567"), an odd mark ("555#123#4567") or the words dash, dot, hyphen or slash is refused. DFARS and FAR clause numbers ("252.204-7012", "52.219-14") are never read as phone numbers. With an SSN or service-number keyword, the digits are read with any separator ("SSN 123/45/6789", "SSN 1 2 3 4 5 6 7 8 9"). Check the record reads a length only from a lowercase m or mm, or a spaced k, before a plain length word, so "2.1M across", "40k long term" and "Budget 5 k around the base year" stay money while "3 m of fencing", "2 m wide" and "10m tall" stay measurements; a race distance ("Run 5k on Saturday") is not money, and "900.000" next to a value word is. The hourly "New in New here" alert leaves out the people a hello's author hid. On a phone, a classic thread that does not open (a hidden hello, a thread by someone you hid, a gone thread or a connection failure) keeps its room header ("← New here"). A linked contract pinned above results it is not part of is labelled "Linked contract · closed" (or "· not in these results"), so the count line is not read as counting it.
- FIX-8 follow-ups (2026-10-17, final verification round 8; owner direction 2026-10-16): one chat check for every place a member writes. Contract, NAICS and grant rooms, classic rooms (New here hellos and Veterans Hall too), replies, private chats, team rooms and the heads-up all run the same check (`talk_body_check`), so a post gets the same answer and the same reason everywhere. What differs by room is about the room, not the words: Veterans Hall posting, read-only government accounts, deadline locks and caps, plus two price profiles: a grant room may restate a public hourly cap, and a team room, where teammates talk price after a signed agreement, skips the price rule but still refuses contact details, SSNs, records and nonpublic information (team rooms had no check before). The check runs in one order: a password, records (SSN, service number, VA file, pasted record text), a tax ID, contact details, prices, nonpublic information, links from new accounts. "Social Security" with no number posts in every room. Clock times ("Offers due by 1400 ET", "Our bid team meets at 0700") and counts ("We bid 1500 jobs last year", "Offers from 1200 vendors") are not prices. A contact word (call, text, phone, number, contact) counts only within three words before a number, and not in "number of", "call volume" or "contact center"; numbers in a list ("Rooms 101 205 3300", "Sizes 120-240-1440", "Order 250-500-1000 gallon tanks") are not a phone number unless a contact word comes first. "@ana.lee" is a mention, never an address; a notice number before "@ highergov.com" is not a mailbox; "joe.smith at army dot mil" and "My email is jsmith at acmecorp.com" are refused, "Register at sam.gov" posts. After an SSN keyword, any nine digits in any grouping are an SSN ("SSN 12-345-6789", "ssn: one two three four five six seven eight nine"); "S/N 123456789" is a serial number. Check the record reads money generously (a capital B, M or K, "mill", comma figures of 10,000 or more, figures after paid, billed, ran or was) and leaves a line out when in doubt; units, lengths and races are not money. On a phone the folded message box (classic rooms, threads and contract rooms) is one line while empty and grows with its words, so a draft kept after a refusal is there to read whole (FIX-1 folded it to one line).
- FIX-9 follow-ups (2026-10-17, final verification round 9; owner direction 2026-10-16): a plainly written phone number never posts. A US phone number written the usual way (ten digits in 3-3-4 groups split by dashes, dots or spaces, or run together, with or without (xxx) or +1) is contact details whatever words come before it: "The building manager is 334-555-0147" and "Questions on the items? 334-555-0147" are refused like "Call 334-555-0147". The only list readings left for that shape are round groups ("250-500-1000") and a unit or count word right after ("Order 250-500-1000 gallon tanks"); a run whose first group starts with 0 or 1 (no US area code does) is a list only under a list word that heads it ("Rooms 101 205 3300"). Ten digits after a document label are a document number ("Invoice 2026001234", "Purchase request 1300123456"). Clock times next to price words post ("Bid walk is 0730 at the main gate", "The quote portal opens 0600 and closes 1800", "Price kickoff call 1300 Thursday"), and so do line labels ("CLIN 1001 is the base year price line", "Bid on lots 1200 and 1300 only"); a stated price is still refused ("We bid at 1950", "I plan to quote 48.50 per unit", "We are pricing it at 1.45M"). What an officer said at an industry day, in the Q&A or an amendment is public, and a NOFO award range is not a sell price. Check the record also leaves out small figures after cost words ("They paid 4800 for the repair", "Unit price on the last buy was 37.25"), "per calendar day", comma figures of 1,000 or more and spelled hundreds of thousands. Every message box, the New here hello and team notes included, grows with its words and is one line again once it is empty; a refused hello shows its reason right under the box, clear of the phone dock, and a refused team note keeps its reason next to the box (team notes say plainly that phone numbers, emails, Social Security numbers and nonpublic buy information stay out, even there).
- FIX-10 follow-ups (2026-10-18, final verification round 10; owner direction 2026-10-16): safety first. When the chat check is in doubt it refuses, says why, and keeps the draft, so the member can say it another way. A US phone number written the usual way (3-3-4 split by dashes, dots, spaces or nothing, with or without (xxx) or +1, first group 2-9) is contact details in every open room and private chat, with no round-number, unit-word or list-word reading: "The base operator is 910-430-1000", "Jane 334-555-0147 parts and service" and "Records 3345550147" are refused. Only a slash list ("Tank sizes 250/500/1000 gallons"), a first group starting with 0 or 1, and ten bare digits right after invoice, PO, purchase order, requisition, tracking, serial, notice, solicitation or contract number still post. A seven-digit number after a contact or role word ("Site contact 555-0147", "Front desk: 555-0110 ext 4") is contact too. Accepted cost: list-shaped numbers written with spaces or dashes are refused ("Tiers 250 500 1000 seats", "Order 250-500-1000 gallon tanks"); written with commas or slashes they post. A stated own price is refused in every open room, the grant room and private chats, and its clause is never read as a clock time ("My rate is 1500 daily", "Our bid is 1700 Friday", "Our quote is less than 1500"). "per the RFQ", "per Section L" and "per amendment 0002" are citations, so "Quotes are due by 1400 per the RFQ" posts, and so do "Our quote went in at 1130 this morning" and "We bid on the 1400 site visit slot". What an officer said is public only when the post names the public place and says nothing like not, yet, before, until, won't or keep it off: "The CO said at the industry day that the ceiling is 4.5M" posts; "The CO said the budget is 2.1M, it is not on SAM yet" does not. Team rooms, which only teammates read, take phone numbers, emails and prices again (trading contact details after an NDA is what they are for); Social Security numbers, tax IDs and nonpublic buy information stay out there too. Open rooms and private chats point to a team room or Reach out (Pro) for contact details, never to a private chat, which refuses them too. Check the record also leaves out figures after quoted, bid, ran, got, charges, is, fee, amount, shipping and each. A worst-case 2,000-character post is checked in under 150 ms.

- FIX-11 reverted (2026-10-18): the round-11 chat-filter migration (20261018000000_fix11_tighten_durations.sql, never applied) was removed after its independent recheck found six regressions against FIX-10 (stated prices posting again, normal talk such as "Our proposal is 85% done" or "Contact SBA @ sba.gov" refused). The chat check stays at the FIX-10 rules. Known false refusal kept by that choice: duration phrasing next to "we offer/quote" ("We offer 24 hour service") is refused as pricing with a reason; members can write "24/7" or "around the clock". The private chat refusal keeps its FIX-11 screen-reader fix (role=alert, aria-describedby). Pattern rules cannot read every phrasing; an AI moderation pass on borderline posts is the recommended next step.
- R1 reconcile, client words (2026-10-19): the independent path reads "Independent specialist" wherever a member sees it ("1099" named a worker classification FedM8 does not decide); the stored role stays `ind`. NDA and teaming-agreement ticks read "Marked by member": the member said so, and FedM8 does not see or check the papers. A Pro member starts a team room, and invited teammates join on any plan; Reach out stays Pro. The team lead reads "Prime" only when `team_detail` returns `lead_prime_eligible`; otherwise "Lead" with one quiet line, "Prime eligibility not checked: <first blocker>", and an older server counts as not checked. Notice revisions are Basic, as the server has it. "Suggest me" is off until the member turns it on, and the line under it says what turning it on shows. Sign-out clears Proposal Studio's local drafts (`fedm8_studio_session_*`). The error log sends the page path and the hash route only, never a query string or what follows "?" or "&" in the hash. os.html loads Google One Tap with the same plain script tag as the homepage.

## R2 pursuit slice (staff preview behind pursuit_v1), 2026-10-18

Contract: `docs/pursuit/R2-CONTRACT.md` section C. Client: `assets/pursuit.js` and `assets/pursuit.css`, loaded as their own files (not bundled). Every screen hides itself unless the signed-in `pursuit_status()` says enabled; the flag is never read from the browser flag list.

References consulted (hi R7/R23). Refero, rendered in Chromium on 2026-10-18 (notes and screenshots kept with the build notes, not in the repo):
- Notion, "warm paper notebook under afternoon sun", https://styles.refero.design/style/2bf4c61f-de10-4614-ba1b-20c0453bd2a9. Taken: warm off-white ground; hairline 1px borders instead of shadows; one colored primary action in an otherwise ink-only screen; lighter ink for secondary lines instead of new colors.
- Linear, "midnight precision instrument", https://styles.refero.design/style/90ce5883-bb24-4466-93f7-801cd617b0d1. Taken: compact rows with hairline separators; monospace for file names and short hashes; the one accent reserved for the action. Its dark palette is not used.
- Intercom, "warm cream editorial spread", https://styles.refero.design/style/12255b63-e506-4bc1-a4cd-d05487de32f3. Taken: hairlines on cream and a small mono caption under a quote as the source label ("<file> · <section> · sha <12 hex>"). Its violet is not used.
- Build pack (owner planning concepts, hierarchy only; their names, dates, counts and copy are not facts): 01 requirements and source (rows, a selected row, a source drawer, one interest action, "No commitment"); 02 private team workspace (Work · Opening · Status rows, a drawer with cost and evidence, a focused next action); 03 contract chat and interest (a phone sheet that names the recipient, Where / Need / Proof, View source, availability, what is shared, one action). The build pack's top nav (Work / Contract Chat / Veterans / My work) is not used: the approved rail, phone dock and NAV_ORDER stay. Approved tokens win where the concepts differ (paper `#fffef9`, canvas `#f5f3ec`, olive `#526547`, serif h1/h2).

Decisions:
- Three places, no new section: "Requirements" at the top of a notice's "Notice & requirements"; "Work and openings" on the team page right under the stage bar; the respond page `#/opening?id=` (hidden route; the rail marks Contracts). Team Up > Teams adds "Openings and responses" (Invited, Your responses, Pursuits you lead).
- One primary action per state, then one line that says the consequence. Requirements: Add to work package (Pro lead), Open your pursuit (lead without Pro), Respond to <company> (one opening), See openings (N) (two or more), else Save ("Keeps it in your pipeline. Nobody is told."). Start a pursuit is a quiet link, never a second button. Team page: the first of Add work, Confirm scope, Create opening, Open it, Invite, Review responses; members get rows only. Respond page: Send response or Update response, with "No commitment. <company> decides who to talk to next."
- Rows, not cards: a requirement row is the title (one or two lines), then section · kind · file, with "View source ›" at the right (just "›" on a phone; the full name stays the accessible name). Which work package already holds a line shows only while the lead is picking lines.
- Honest source: completeness counts first ("1 of 3 files read. 1 could not be read. 1 did not download."), then "Found by reading the files. Not checked by a person." The drawer quotes the exact excerpt, the file, the section, a 12-character hash, the read date, "Not checked by a person", "Sorted by a model, not checked" only for model-typed lines, a closed "Text around it" for full readers, and warnings for a changed file or a retired line.
- Blockers are an ordered list in ink with plain numbers, under "Still to do", never red, never pills, never a score. "Resume permission needed" shows on a shortlisted person and says what comes next ("Asking for resume permission comes next. Nothing is shared yet.").
- Drawers: right side on desktop (520px), full screen over the dock on a phone (z-index 120), focus on the title, Tab kept inside, Esc and Close close, focus goes back to the control that opened it (or its re-drawn copy), the page behind is inert. Drawers do not write history. Yes/no questions (withdraw, close an opening) are small centered dialogs.
- Respond page: one column (560px), paper card, left-aligned with the page. The footer with the primary action stays pinned above the phone dock (`calc(89px + env(safe-area-inset-bottom))`) while the form is open and stops being pinned once the receipt shows. What will be seen is a checklist from the member's own card: the public name is always on; everything else starts off; empty fields read "Not on your card" and cannot be picked. "Not shared: your resume, email, phone and UEI." is always visible. The receipt appears only after the server returns a stored row, and focus moves to its heading.
- States in words, no skeleton people or counts: Loading…, That did not load. + Try again, We could not confirm it was sent (retry sends with the same key, so nothing sends twice), You're offline (the draft stays in this tab), paused and closed lines that keep the draft, This is not open to you, This page is not open yet (flag off). A refusal shows the server's own sentence above the footer with focus on it, and the field it is about is marked.
- Words: one frozen table, `WORDS` at the top of `assets/pursuit.js` (contract C.7 plus a few keys the screens needed, listed in the slice report). The section rows and opening lists skip glossary underlines (`data-gloss-skip`) so short meta lines stay calm; full sentences keep them.
- On the notice and the team page the page title row and the section photograph come from the approved shell and stay. The respond page is the exception (verifier fix, 2026-10-19): the opening title is its only h1, so the shell title stays hidden there (`os-boot.js` homeView, `approved-design.js` decorateHeading), and no section photograph or Contracts tabs sit above the sheet (`decorateTopicImages`, `applyNav`); the rail still marks Contracts. The sheet starts the page on desktop and phone. Controls are the approved `.btn` (olive) and `.btn.ghost`; every `.pv-*` control is at least 44 × 44; focus ring 2px olive; no transitions; colors only from `--fd-*`.
- Verifier fixes (2026-10-19): the `opening` route is marked `tool: false` and All tools (`assets/os-everything.js`) never lists it, with the flag off or on; it is a page reached only from its own link. Match-M8 puts no Chase / Pass chip on `opening_invite`, `opening_response` or `response_update` alerts in the Inbox (`assets/jev-match.js` reads each alert's kind): they carry the notice id but are about a person or a team, not a match. "Set up your card" opens `#/team-profile?kind=person` on the employee and independent paths and `?kind=company` on the company sub path, so a person is never sent to the company form and SAM. The funded choice reads "Funded (the team recorded a win)": FedM8 does not check an award, so the words say what the team recorded, not that an award was won.

## R3a sharing and participation (staff preview behind pursuit_v1), 2026-10-19

Contract: `docs/pursuit/R3A-CONTRACT.md` section C. Client: `assets/pursuit-share.js` (its own file, not bundled, loaded right after `assets/pursuit.js`) and one R3a block appended to `assets/pursuit.css`; hooks in `assets/pursuit.js`, `assets/os-teamup.js`, `assets/os-boot.js`, `assets/approved-design.js`, `assets/os-views.js` and `assets/jev-match.js` are guarded, so with the file missing, its status off (`pursuit_share_status`) or an R2-shaped server reply the R2 screens render exactly as R2.

References. No new reference was opened for R3a. The screens reuse the three Refero references recorded in the R2 section above (rendered 2026-10-18): Notion https://styles.refero.design/style/2bf4c61f-de10-4614-ba1b-20c0453bd2a9 (one colored primary in an ink-only screen, hairlines instead of shadows), Linear https://styles.refero.design/style/90ce5883-bb24-4466-93f7-801cd617b0d1 (compact rows with hairline separators, one accent for the action) and Intercom https://styles.refero.design/style/12255b63-e506-4bc1-a4cd-d05487de32f3 (hairlines on cream, a small caption under a line as its label). The build pack's interest sheet (03) set the consent sheet's hierarchy: recipient first, then what, why, for how long. The approved tokens are unchanged; no new color, font or component.

Decisions:
- Screens: "Your resume" on the respond page (after "What <company> will see"), "Your part in this team" above the respond form, a workload note inside "Your availability" that only the member sees, lead rows in the opening drawer (resume line, naming line, participation line, Select / Release / Replace), My sharing (`#/sharing`) and Company representatives (`#/reps`). Both new routes are hidden from the rail (the rail marks My Profile), never a tile in All tools, keep the shell title, and say "This page is not open yet." while the flag is off, with one exception (round 1): while the flag is off and a permission the member gave is still open, My sharing shows only "Who can open your resume" with Stop sharing under a plain line that the feature is off, and My Profile keeps its "Who can open your resume" link, so a member can always stop sharing. Team Up > Teams adds "Needs your answer" and two quiet links.
- One primary action per state. The participation block owns the primary when it has one (Accept the scope, Accept the new scope, Confirm participation, Confirm again, Choose) and the respond footer steps down to a ghost button; Step back is always a quiet link. On My sharing the first "Choose" is the page primary and every other control is a ghost button, including the availability "Save" (it is the primary only when no request waits); on Company representatives the first of Accept and Add a representative is.
- The consent sheet hierarchy: a real checkbox "Let <company> open my resume", unchecked and never pre-checked; checking it reveals, in this order, the version (read only), why, who (that team only), how long (30 / 90 / 180, 90 picked) and the rule line. The grant dialog repeats the same facts with the recipient in its title. Applying and being named are two separate permissions; the respond page never offers naming.
- The cannot-recall line: "Stopping sharing stops new opens right away. Copies or links a team already took cannot be recalled." is always visible at the top of My sharing in ink at reading size (not small print); the Stop sharing dialog says the same for that team ("This stops their new opens of your resume right away. Copies or links they already took cannot be recalled."), and the toggle rules and the grant dialog keep "Copies already downloaded cannot be recalled." No word claims a team loses access the moment the member stops or withdraws (round 2): the server stops every new open, but it cannot recall a link a lead's browser already signed.
- Receipts only after the server stores a row: the resume permission runs after the response is stored and its result joins the receipt; a failed permission never hides the stored response and offers "Share my resume" with the same key. Stop sharing moves the row to Ended from the server's reply and focuses a status line that says so.
- Rows, not cards: each permission is a hairline row headed by the recipient's name, then purpose, version and until-date, then how often it was opened; Ended is a closed `details` with a count and a per-row History; both keep their open/closed marker at every width (the R3a CSS block outranks approved-design.css's phone `details > summary { display:flex }`). A permission the team cannot open right now stays a row with a plain paused line ("Paused while your card is paused." or "Paused. This team cannot open it right now."), never reads as active, and keeps Stop sharing. No pills, nothing red, no scores; stages are plain words ("Selected", "Scope accepted", "Confirmed", "Needs re-confirmation").
- The workload note and saved availability never render on a lead screen, even when a payload carries them. Open resume names itself "Open resume (opens a new tab)", signs a 60-second link only after the audited open, and never renders or stores the path; its line says only "Opens in a new tab. FedM8 records each open." because the server cannot cap a link the browser signs. The respond receipt says what was shared in one sentence ("They can see what is listed above and can open your resume until <date>.") and keeps "Nothing else was shared." only when nothing else was. An update, or a response to another opening of the same team, while a permission to that team is open says the same until-date sentence (round 2). Withdrawing a response says, in the same dialog, what happens to an open resume permission, from the server's `ends_on_withdraw` (round 2): one given with that response ends, so the team cannot start a new open (copies or links already taken cannot be recalled), and the page then reads "Off" (or, while a naming permission to that team still runs, "Off for reviewing you" with the date it can still open the resume to name them); one given another way (with another response to the same team, or on the team route) keeps running, so the dialog says until when the team can still open it and that it can be stopped in My sharing, and the page keeps its line. A company representative is offered no Withdraw while the company is selected (only the owner or an admin can).
- Round 3. Step back says what ends with the selection, from the server's `ends_on_step_back` on the naming permission: one given on that selection ends too ("so they cannot start a new open", copies or links already taken cannot be recalled), and when the permission to review the member is still open the dialog says that one stays until its date instead of claiming the team cannot open the resume; a naming permission given separately says it stays until its date; an older reply adds nothing. My sharing names a selection that ended for the team's reasons ("Ended on <date> when the team ended your selection.") and never says "You stopped sharing" for something the member did not stop. With the flag off, or nothing open, the lines say no team can start a new open, and the cannot-recall line sits on the same screen. On the respond page exactly one status region speaks after Accept, Confirm or Choose (the block moves focus to its heading and has no status region of its own; round 4 moved that region from the "Where it stands" line to a hidden announcer kept through reloads). The respond footer's line follows the selection: "Updating your response does not change your selection." while selected, scope accepted or re-confirming, "You confirmed on <date>. This is not a contract or a job offer." once confirmed, and R2's "No commitment" line only without an active selection. Inbox chips give every pursuit alert kind a plain label (Resume request, Resume permission, Selection update, Company representatives, Opening invite, Response, Response update).
- Round 4. One verb for one action: a member who steps back reads "Stepped back" and "You stepped back on <date>." whether or not they had confirmed ("withdrew" stays for withdrawing the response), the respond page's "Where it stands" line goes back to the response's own status once the selection ended, and My sharing says "Ended on <date> when you stepped back from this opening." One announcer: a visually hidden status line made once per respond page and kept through every reload says the result of an action about 100 ms after the new page is in place; a reload keeps the old page in view (busy) instead of flashing "Loading…", and the note count and workload note speak only once the member is in those fields. Dialogs read their consequence sentences when they open (described by their body), and a radio group is one tab stop at its checked choice. The lead's Release and Replace say when the permission to name the member ends too. In the Inbox the highlighted row is the one the pane shows, the box tabs keep focus, the item's own action is the one filled button ("Next unread" is quiet), company representative alerts carry the same name in the row, pane and chip, and a hovered or tapped selected tab keeps its olive fill. With the flag off My sharing heads its list "Permissions you gave". Tokens unchanged; the only CSS change is the selected-tab hover rule in `assets/approved-design.css`.
- Round 5. Words stay true in every state the server can produce: withdrawing while selected says "Your selection for this opening ends too.", reads the page again (no Choose or Step back is left beside "Respond again"), and the block then says "The selection ended on <date>, when this response was withdrawn." (never "You stepped back"; a selection the page cannot place reads "The selection ended on <date>." and the lead's stage word "Selection ended"); the Withdraw and Step back dialogs say "cannot start a new open" only when the server says the lead keeps no other permission, and otherwise say the other permission is not affected (it may be paused, so nothing claims the team can open it); with the box off the line is "Off. This response does not let <team> open your resume." The Replace dialog names the member ("Your permission to open <name>'s resume ... ends when you replace them.") after the choice. Focus and speech: a held reload leaves the old page in view but inert and closes any dialog opened from it; the first load marks the host busy with one plain "Loading…" line (no status region anywhere a page draws a Loading line); the lead drawer has one hidden announcer that says the result ("You released <name> from this opening.") once the rows are back and focuses that row. In the Inbox the open row carries a 4px olive bar (`#526547`, above 3:1 against unread and read rows) and the focus ring while the list has keyboard focus; on a phone opening a message moves focus to its heading and Back returns focus to the list on that row. Tokens unchanged; the only CSS change is the open-row rule in `assets/approved-design.css`.
- Round 6. How a selection ended comes from the server now (`end_cause`), not from dates: a member who stepped back and then withdrew still reads "You stepped back on <date>.", and a selection that ended with a withdrawal still reads "The selection ended on <date>, when this response was withdrawn." after the response is sent again (the dates are kept only for an older server). On the lead's row the head is the row's focus target, so it shows a stage word only while the selection is active; once it ended the head shows the response's own status ("Sent", "Shortlisted") and the line below says how the selection ended ("Released", "Stepped back", "Selection ended"). The lead's blocker for a selection that ended on the member's side reads "The person you selected is no longer taking part. Select someone else." for a step back and a withdrawal alike. When a refusal makes the page read the server again, the alert no longer asks for that reload: a resume that changed while the grant dialog was open reads "Your resume changed. Choose again to share the version now on file." (or "Your resume changed, so nothing was shared." when there is nothing to choose now), and work that changed reads "The work changed since you opened it. The page now shows the latest."; where nothing reloads (the receipt's retry) the server sentence stays. Tokens and CSS unchanged.
- Round 7. A company response in the lead's drawer works like a person's: Select, then Release or Replace, with the participation line under the shared fields ("Selected <date>", then "Released · <date>" or "Replaced · <date>"); while it is selected, Release and Replace take the place of Undo and Decline, and the head shows "Selected" only while the selection is active. A company row never shows a resume or naming line. On My sharing, a grant from a team row ("Share for review", "Allow naming") that the server refuses because the resume changed now reads "Your resume changed, so nothing was shared. Share it again to use the version now on file."; "Choose again" is said only after a request's Choose whose request is still on the page. When the server is busy deleting a card or account it refuses a grant with "This is changing right now. Try again in a moment.": the grant dialog stays open with that sentence in its error summary (focused) and Allow still enabled, and the respond receipt keeps "Share my resume". Tokens and CSS unchanged.
- Round 8. A member who owns a company card and represents another company, or represents two, sees the shown response's company on the respond page: a representative reads "The company card owner or an admin accepts, confirms or withdraws for <company>." and is offered nothing the server would refuse; "Responding for" starts on that company. (Round 9 replaced the in-page switch that changed only the button text; see below.) On a company opening the lead's blocker reads "The company you selected is no longer taking part. Select another company."; it is gone once the selection's response was sent again. The respond receipt says "Try again." only when there is no server sentence and "Share my resume" is offered; otherwise it reads "Your response was sent, but sharing your resume did not go through." and the server's sentence. After "Share my resume" focus stays on the receipt's sent line (or moves to the retry, or to the alert when there is nothing to retry). In the lead's drawer a refused Select or Release that means the row changed reads the rows again, focuses that row and says why; any other refusal shows the alert under the row and focuses the button again. Tokens and CSS unchanged.
- Round 9 (orchestrator decision). The respond page shows exactly one company card at a time. "Responding for" sits above "Where it stands" as a short list of hairline rows, one per card the member may act for: the card on the page reads "On this page" in plain green-dark words (no pill), every other card has a ghost "Switch" button (named "Switch to <company>"), a paused card says "(your card, paused)" or "(you represent it, paused)", and a card with a response here says "Has a response here". It is a list of buttons, not a radio group, so arrow keys never reload the page. Switch keeps the card in the URL (`&as=<profile_id>`, replacing the address, so Back and a reload stay on it), reads the page again for that card with the old page in view and inert, then moves focus to the sheet heading and says "Now responding for <company>." once. Everything below then belongs to that card alone: its own name, NAICS and set-asides under "What <company> will see", its status, its selection block, "Update response" for its own response or "Send response" for none, the footer line, the receipt and the Withdraw dialog. With two or more cards and none in use the list asks "Pick which company you are responding for." and the form waits for a pick. When the card on the page is one the member represents and it cannot respond, the words are about that company: "This company card is paused. Its owner can turn it back on.", "This opening is not taking responses from <company>.", "<company> is on this team already."; the list stays, so the member's other active card is one Switch away. Drafts are kept per opening and per card, so nothing typed for one company appears under another. Tokens unchanged; one small CSS block for the list rows (`.pv-for-*`, 44px rows and buttons).
- Round 10 (orchestrator decisions). Words that are true whoever acts for a company: on a card the member represents the respond page names the company, never "you": "This response was withdrawn on <date>." (on every company card, since the owner, an admin or a representative may have withdrawn it), "Name as members see it", "Set-asides <company> listed (self-reported)", "Not on <company>'s card", "Availability", "They can message <company> on FedM8 after you respond.", "Withdraw <company>'s response?" / "<lead> will see that <company> withdrew.", "Updating this response does not change the selection.", and "Your part in this team" says "<lead> selected <company> on <date>.", "<company> accepted the scope ...", "<company> confirmed on <date>." on every company card (an admin may accept or confirm for the owner). Person paths keep "you". A hold is never called paused: the member's own held card reads "Your Team Up profile is on hold. Write Support." and "(your card, on hold)", a represented one "This company card is on hold. Its owner can write Support." and "(you represent it, on hold)". A block names the company only when it is between the company's owner and the lead; the member's own block reads "This opening is not taking responses from you." on every card. "Responding for" reads "Each company responds on its own. Pick a company to see its details and its response.", and after a switch the one announcement is "Now showing <company>." followed by the reason when that card cannot respond. A switch whose read fails keeps the page in view and usable (nothing inert or busy, the address back to the card shown), adds one plain line under the list ("<company> did not load. This page still shows <company>.") with a ghost 44px Try again that gets focus, and the announcer says the line once; Try again repeats the switch and then focuses the heading as any switch does. On an invite-only company opening only the invited cards (or one already responding) are listed. Hub rows about a company card ("Invited", "Your responses", "Needs your answer") open the respond page on that card. Tokens unchanged; one small CSS rule for the failed-switch line (`.pv-for-error`).
- Round 11 (orchestrator decisions). After a refusal only a reload (or setting up a card) can get past ("This opening takes responses only from the companies its team invited.", "You cannot respond for that company now. ...", "This changed in another tab. Reload to see the latest.", or "Set up your person card first. ..." after Send), that step is the one filled button in the error summary and Send turns ghost and disabled, so the page never offers a filled button that can only repeat the refusal. Reload ends like a switch: the page read again focuses its heading and, on a company opening, says once which company it shows. When it shows another company than the one asked for (after Reload, or after a switch to a company the member no longer acts for), one plain ink line sits above "Responding for" (or above "Where it stands" when only one company is left): "<company> is not one of the companies you can respond for now.", and the one announcement adds "Now showing <company>.". A Reload that does not load keeps the page and its summary says "That did not load." with Reload, focused. The hub keeps "Your responses" for the member's own cards and lists the companies they represent under "Responses for companies you represent"; a "Needs your answer" row for a represented company names it ("Accept the scope · <company>"). Tokens unchanged; one CSS rule for the line (`.pv-for-gone`) and one for a filled step in the error summary.
- Round 12 (orchestrator decisions). When the respond page lands on another company than the one asked for and shows a card, the plain ink line says both sentences, so a sighted member reads which company the page and its Send are for: "<company> is not one of the companies you can respond for now. Now showing <company>." In the Pick state (two or more companies, none on the page) the line keeps the first sentence alone and the list below asks which. The line is not a live region, so the page still speaks once. A Team Up hub row that opens the page (&as=) of a company the member represented and no longer acts for ends the same way (the line, one announcement, focus on the heading, the card dropped from the address), also after Try again when the first read fails. The member's own company card is an open decision (contract C.14 item 83). Company names are put in as written, whatever characters they hold. The hub splits "Your responses" from "Responses for companies you represent", and names each represented company, from the server's own row fields, so the split stands even when the sharing status read fails. Tokens and CSS unchanged.
- Words: `WORDS` at the top of `assets/pursuit-share.js` (contract C.10 plus a few keys the screens needed: `common.cancel`, `common.close`, `lead.resume.openName`, `reps.inviteName`, `reps.removeName`, `reps.roleWord.*`, `change.bodyOne`, `change.removeBodyOne`, three catalog sentences); field labels and shared state lines come from `assets/pursuit.js` WORDS, which gains the six A.2.7 blocker texts. Phone (375): every row stacks, action buttons go full width, the 30 / 90 / 180 choice stays one row, a paper strip fills the gap between the pinned respond footer and the dock, dialogs follow the R2 drawer rules, 44 x 44 targets, no horizontal scroll (checked with the harness at 375 x 812, and text contrast of every new screen at 4.5:1 or better).

## R3b evidence and quotes (staff preview behind pursuit_v1), 2026-10-19

Contract: `docs/pursuit/R3B-CONTRACT.md` section C (and F.5, F.6). Client: `assets/pursuit-files.js` (server-signed downloads), `assets/pursuit-evidence.js` (My evidence, the item drawer, the lead's Evidence section, readiness) and `assets/pursuit-quotes.js` (the composer, "Your quote", the lead's Quotes), each its own file (not bundled), plus one R3b block appended to `assets/pursuit.css`. Every hook in `assets/pursuit.js`, `assets/pursuit-share.js`, `assets/os-teamup.js`, `assets/os-boot.js`, `assets/approved-design.js`, `assets/os-views.js` and `assets/jev-match.js` is guarded, so with a file missing, its status off (`pursuit_evidence_status`, `pursuit_quote_status`) or R3b not applied (`PGRST202`) the R2 and R3a screens render exactly as before.

References. No new reference was opened for R3b. The screens reuse the three Refero references recorded in the R2 section above (rendered 2026-10-18): Notion https://styles.refero.design/style/2bf4c61f-de10-4614-ba1b-20c0453bd2a9 (one colored primary in an ink-only screen, hairlines instead of shadows), Linear https://styles.refero.design/style/90ce5883-bb24-4466-93f7-801cd617b0d1 (compact rows with hairline separators, tabular figures, one accent for the action) and Intercom https://styles.refero.design/style/12255b63-e506-4bc1-a4cd-d05487de32f3 (hairlines on cream, a small caption under a line as its label). The build pack's 02 private team workspace concept, as recorded in the R2 section (a drawer with evidence and cost details next to Work · Opening · Status rows), set where evidence and cost sit: two quiet rows in the package drawer and a separate section under "Work and openings". The approved tokens are unchanged; no new color, font or component.

Decisions:
- Screens: My evidence (`#/evidence`, one 720px column: whose evidence, waiting for your answer, your evidence as rows, the retention line), the item drawer (520px right, full screen on a phone: kind, facts by kind, how it was checked, the file, who can see it), the share dialog, the request answer view (`?request=`) and the same view for one opening (`?opening=`); the lead's Evidence section on the team page right under "Work and openings" (private, one row per requirement line, "Requirement line · Evidence" as a two-column table on desktop and stacked blocks on a phone, live links in a closed `details`); "Where it stands" in the opening drawer (four separate states in a plain `dl`: who is doing it, confirmation, evidence, pricing; pricing hidden while quotes are off); the quote composer (`#/quote?opening=`, a 960px column); "Your quote" on a company respond page; the lead's Quotes in a company opening's drawer. Both new routes are hidden from the rail (the rail marks My Profile for evidence and Contracts for the composer), never a tile in All tools, and keep the shell title.
- One primary action per state. On My evidence the first "Answer" is the page primary while a request waits, else "Add evidence" (hidden for a representative). In the drawer "Save" is the primary while the form changed; after a file replacement the first "Share again" is the primary while the form is unchanged. The request view's primary is "Share" ("Add new evidence" when the card has none); "Not now" is a ghost button that asks first. The composer's primary is "Save draft" while the form differs from the saved draft, "Send quote" for a saved draft (owner or admin), or "Make a new version" after a decline, an expiry, a withdrawal or a needs-review; on a sent or accepted quote it is a ghost button with the line that a new version replaces this one. On a paused, held or blocked card nothing can be done, so the composer shows the reason line and no primary, no "Make a new version" and no draft form (R3c). With one company card, a representative's or an admin's composer names the company above the reason ("Sending for <company> (you represent it)."), and a composer that ends in one line (not open to you, not open yet, or the server's refusal) puts focus on that line and offers "Back to Contracts", so a quote alert's Open never leaves focus on the page body (R3c review round 4). The team page and the drawers keep R2's primary: every evidence and quote action there is a ghost button.
- The cannot-recall line: "Stopping sharing ends a team's access right away. Copies a team already downloaded cannot be recalled." sits at the top of My evidence (and of My sharing, F.6) in ink at reading size. It is true from this PR: every evidence and resume open is a 60-second download the worker signs after an audited open, the evidence bucket is born closed to every non-owner, and migration 7 closes browser reads of other members' resumes (H.4). Every stop, remove, withdraw and step-back dialog repeats that copies already downloaded cannot be recalled (review round 2 brought the withdraw and step-back lines into line).
- Download-only files: "Download file" and "Download resume" name themselves "... (saves a copy to your device)", start the download through a hidden link (no new tab, no popup) and say "Your download started. The link works for 60 seconds." No path is rendered, stored or logged. The file rules say what the check is and what to leave out (Social Security numbers, a DD-214, medical records). Since R3c (2026-10-20) they read "PDF, Word (.docx), PNG or JPEG, up to 10 MB. Images can be up to 25 megapixels, and a PNG up to 20,000 pixels on a side. Before anyone can open a file, FedM8 checks that it is the type it says and is not damaged, and scans it for known viruses. PNG and JPEG images are rebuilt, which removes hidden details such as location."; no sentence claims more than a scan for known viruses, and an image over 25 megapixels, or a PNG with a side over 20,000 pixels (the worker's own cap; R3c release prep), is refused from its header as soon as it is picked, and whatever file is picked last, of any type, is the only one that uploads (R3c review round 2). The lead's board says the same beside a checked file ("FedM8 checked that the file is the type it says and is not damaged, and scanned it for known viruses. It did not check whether what the file says is true.") and only "File being checked" beside one still being checked. A file being checked reads "Being checked. Nobody can open it yet." and the page announces the result once. Under a ready file, a newer upload that failed reads "A newer upload on {date} did not pass the check:", then its reason, then "The current file stays.", so a reason that says "this file" or "it" is about that upload, never the file still shared (R3c review round 3).
- Honest verification: three words only, "Self-reported", "Source checked" (an award record or a SAM listing for the verified UEI, with the record's own figures beside it and "The other details are as you entered them.") and "Reviewed by <team>", always followed by "This is not an official verification." The lead's form names the owner ("went to Sam S.'s verified UEI"), never "your verified UEI". A lead's own evidence stays "Needs confirmation" on their own board with a line saying why. Requirement lines read Supported, Needs confirmation or Missing, with Expired and File being checked as plain words; nothing is a score, a percentage or a pill, and nothing is red.
- Prices only in the quote channel: amounts render from integer cents with `Intl.NumberFormat` in the composer, the lead's Quotes and the send and accept dialogs, nowhere else (no alert, Inbox pane, hub row, readiness word or package row carries one). Alternatives are listed under "Alternatives, not in the total" and are never added to the total or to each other; the totals panel says FedM8 works the figures out again on save, and after a save it shows the server's figures. Quote lines are a real table with column headers on desktop and one fieldset per line on a phone, each input labelled with its line number; the composer footer pins above the phone dock like the respond page, in two rows on a phone (the one primary across, the ghost buttons side by side).
- Screenshot review (1440 and 375): long choices (requirement lines, items, purposes, who to ask) read one per line with the control at the first line, short ones (days, kinds) keep the grid; a reload of the lead's Evidence section keeps opened lines open and puts focus back on the control used; the owner's own profile card offers "Download resume" too.
- Review round 1 (2026-10-19, re-shot at 1440 and 375): after every write the section's status line says what happened and takes focus (accepting or declining a quote, asking for or cancelling a quote request, withdrawing a quote, cancelling an evidence request, removing a link or a file); Cancel on an upload waits for the call in flight ("Stopping the upload.", then "Upload cancelled.") and never finishes the cancelled file; an upload that never finished reads as unfinished, never as being checked; "Ask to use it in the proposal" asks first and names the person and the item; the work a quote priced shows one "When" row; the totals panel speaks only when its figures change; no glossary tab stops inside the share dialog, the sharing rows or a request's lines; the six evidence and quote Inbox chips use the row's words; the privacy paragraph names a company card's admins and representatives and every reference field.
- Review round 2 (2026-10-19, re-shot at 1440 and 375): after a quote write the opening drawer is drawn again from the server, so "Where it stands" and the blockers never keep the old pricing state beside "You accepted ..."; asking a company for a quote or an updated quote and cancelling a quote request ask first and name the company; each Decline and Ask for an updated quote names its company, and the Accept dialog's other button is "Not now"; "Your quote" on the respond page names its company and follows the "Responding for" choice; Mark reviewed and Not now on a request say what happened and take focus, and a request that can no longer be declined never says "or say not now"; a representative's share dialog says review only; a member's past project reads "Role on the contract" to the lead; the lead's board tables add no glossary tab stops; the file block keeps one status line between redraws and dates an earlier rejection; a staff preview's hidden link names its owner and says why.
- Review round 3 (2026-10-19, re-shot at 1440 and 375): the composer's "Sending for" is a list with the company on the page marked and a "Switch" button for each other company (never radios that change the page on an arrow key), the heading takes focus on arrival and a switch says which company the quote is now for; a quote request's "Not now" sits beside its request line at the top, and both "Not now" dialogs say "Keep the request"; after the lead asks for an updated quote the company's row says so with its Cancel instead of telling the lead to ask; each lead quote row is a heading and "Totals" nests under its version or row; read-only lines say "Alternative"; the hub lists one quote row per opening and company with its states and dates under "Quotes"; a ready file never shows an older rejection, and a representative reads a rejection without a remedy or the upload rules; the item drawer adds no glossary tab stops; the board's Mark reviewed, Remove from this line and Cancel request name their item, line or recipient; "Where it stands" shows "That did not load." with Try again instead of vanishing; the rule lines name websites, links and social or chat handles.
- Review round 4 (2026-10-19, re-shot at 1440 and 375): a focused control is never hidden under the fixed header, the composer's pinned footer or the phone dock (WCAG 2.2 2.4.11): while a quote or evidence page shows, `html` reserves their room with `scroll-padding`, and the quote and evidence scripts move the page by whatever still overlaps the focused control after the browser's own scroll (dialogs and drawers scroll inside themselves). Since R3c the team page does the same: `mountTeam` marks it `.pv-team-page`, `html` reserves the header (76px desktop, 72px phone) and the phone dock with `scroll-padding`, and `onSheetFocus` moves keyboard focus clear of both, leaving the Evidence section (`.pv-evidence`) to its own guard. A local check names its field, and on a quote line its line ("Unit, line 4: Each line needs a unit ..."; "Aggregate: Enter dollars and cents ..."); the summary takes focus and holds a "Go to" button for that field. Discard draft says what it deletes and keeps with "Keep the draft", Withdraw keeps with "Keep the quote"; "Not yet" is left only for Send. A sent quote the team never accepted says "Sending a new version replaces this one for <team>."; only an accepted one says the team will need to accept the new one. The request view lists live shares under "Already shared with <team>", and Not now never says "Nothing is shared" while one stays. A representative's empty company card says its owner or an admin adds evidence. A file refused before upload keeps focus on a file input (Replace opens again). Every accessible name starts with its button's visible words ("Download file: ...", "Ask to use it in the proposal: ...", "Ask for a quote: ..."). A shared file that cannot be downloaded now offers no Download and says why Mark reviewed waits; the owner reads "This file cannot be opened." for a stored object that changed after the check. A share that ended with its selection says "Ended on <date> when the selection ended."
- Review round 6 (2026-10-19; the My evidence screens still to be re-shot): the guard that keeps a focused control clear of the header, the pinned footer and the dock acts on keyboard focus and on focus the page moves itself, never on focus from a mouse or finger press, so a press is never lost under a moving page. The respond page draws no quote block on the member's own team (it never says "after you respond" where they cannot respond). On a company card the member represents, a paused, held or blocked card reads in the company's words ("This company card is paused. Its owner can turn it back on."), and the evidence page opened from the company link is headed with the company's name. "Write a quote" leaves at once when the response is withdrawn on the page. A refused share never reuses its key, so "Reload and try again" works. The retention line says "with no time limit", and once a team's lead deletes their card or account, the kept records read "A team that has closed" in place of the team's name.
- Words: `WORDS` at the top of each new file (contract C.14 plus a few keys the screens needed and recorded in the contract's C.18 notes); field labels, state lines and requirement types come from `assets/pursuit.js` WORDS, which gains the six A.1.9 blocker texts. A name ending in a period never doubles the sentence's period. Phone (375): rows stack, actions go full width, the 30 / 90 / 180 choice stays one row, drawers are full-screen sheets over the dock, no horizontal scroll; every control at least 44 x 44, focus ring 2px olive, `prefers-reduced-motion` removes transitions.

## R4 proposal package (staff preview behind proposal_v1), 2026-10-23

Contract: `docs/pursuit/R4-CONTRACT.md` section C, with its words in E.1. Recorded before building, as R2 to R3c did: R4-1 (database and docs) ships no screen, and R4-2 builds what this section describes. Client (R4-2): `assets/pursuit-proposal.js`, its own file (not bundled), loaded right after `assets/pursuit-quotes.js`, plus one R4 block appended to `assets/pursuit.css`. Its two hooks are guarded, `mountTeam` in `assets/pursuit.js` and `renderSharing` in `assets/pursuit-share.js`, so with the file missing, `pursuit_proposal_status()` missing or refused, or its status off, every screen renders exactly as before. No route, no Inbox kind, and no change to `assets/os-boot.js`, `assets/os-views.js`, `assets/os-studio.js` or the bundle. The flag is never read from the browser flag list.

References. No new reference was opened for R4. The screens reuse the three Refero references recorded in the R2 section above (rendered 2026-10-18): Notion https://styles.refero.design/style/2bf4c61f-de10-4614-ba1b-20c0453bd2a9 (one colored primary in an ink-only screen, hairlines instead of shadows), Linear https://styles.refero.design/style/90ce5883-bb24-4466-93f7-801cd617b0d1 (compact rows with hairline separators, monospace for short fingerprints, one accent for the action) and Intercom https://styles.refero.design/style/12255b63-e506-4bc1-a4cd-d05487de32f3 (hairlines on cream, a small caption under a line as its source label). The build pack's 02 private team workspace concept, as recorded in the R2 section (Work · Opening · Status rows, a drawer, a focused next action), sets the hierarchy: one Proposal section on the team page, rows, and a drawer for a section or a version. The approved tokens are unchanged; no new color, font or component.

Decisions:
- One place on the team page, no new section or route: "Proposal" sits under Evidence, labeled "Private to this team." The member's own audit rows join My sharing (`#/sharing`) as a block headed "Proposal exports that used or left out your name, evidence or quotes". That block needs sign-in only, so it renders with the flags off too; with the flags off and rows present it takes the place of "This page is not open yet." under R3a's cannot-recall line, and with no rows the page is exactly R3a's off page. R4 adds no link to it.
- One primary action per state, then one consequence line (the R2 rule). A Pro lead with no package sees "Start the proposal package". Then the first true of: "Add a section", "Place the remaining lines", "Review the changes", "Freeze a version", "Open the latest version" (while an entry of the latest version is withheld, so "Record the final review" is never offered when the server would refuse it), "Record the final review", "Export". An accepted member sees "Your sections" (title and state, with a state choice on a section they write) and no primary unless they write a section.
- Rows, not cards. Readiness comes first: independent states in words, the scope line that always shows, then "Still to do" with numbered blockers in ink, never red, never pills, never a score or a percent. Then section rows (title, writer, state, and counts of lines, work, people, evidence and quotes), "What changed" (each impact with its source line and "Mark as reviewed"), "Versions" (number, date, a 12-character fingerprint, and whether the final review is recorded) and "Exports" (number, date, formats, audit counts). The best state reads "Final review recorded"; no screen says "ready to submit", "verified" or "signed".
- Honest source, as in R2: every requirement line reads "Not checked by a person", a model-typed line also reads "Sorted by a model, not checked", and a section FedM8 seeded reads "Found by reading the files. Not checked by a person." A package with no section says so in one sentence chosen from readiness now (no files, lines not listed yet, files partly read, no instruction lines, or listed lines still to place) and never says why it started empty. Evidence shows its verification word followed by "This is not an official verification."; an item past its valid-until date reads "Expired" and counts as not usable.
- No amounts. An accepted quote appears by company, revision number and dates only. The module calls only its own 15 RPCs from a frozen list and never an R3b quote RPC, so no amount reaches the page.
- Drawers follow the R2 rules. The section drawer holds the title, the writer, the position and five item groups whose pickers list only what the server would accept now. The version drawer shows the frozen content resolved now, each withheld entry in its own sentence, "Fingerprint matches." or "This version cannot be shown. Tell support.", and the cannot-recall line. The final review is a small centered dialog with one fixed sentence: "I reviewed this version and the changes listed for it. This is not a submission."
- Export is a dialog with two choices, "Package index (.txt)" and "Compliance matrix (.csv)", built in the browser from the server's reply. Its consequence line says that FedM8 records which names, evidence and quotes it included or left out, that the owners of those cards can see that record, and that copies cannot be recalled. Files download one at a time through the existing file opens ("Download file", with "Same file as frozen"). Replies and names stay in the page's memory: nothing goes to browser storage, and a kit draft holds only a section title.
- States in words, as R2 to R3c: loading, "That did not load." with Try again, and the server's own refusal sentence with focus on it. `terms_pending` goes to the existing legal banner and never reads as off.
- Accessibility (the R3b practice): every repeated button's accessible name starts with its visible words and names its object ("Mark as reviewed: ...", "Download file: ..."); after every write the section's status line says what happened and takes focus; the member's state choice never writes on an arrow key; the section sits inside `.pv-team-page`, so R3c's `scroll-padding` and `onSheetFocus` keep a focused control clear of the header and the dock. Phone (375): rows stack, actions go full width, drawers are full-screen sheets over the dock, every control at least 44 x 44, focus ring 2px olive, no horizontal scroll.
- Words: `WORDS` at the top of `assets/pursuit-proposal.js` (contract E.1; a key the screens need is recorded in the contract's §H); `assets/pursuit.js` WORDS gains the A.1.8 blocker texts. The screens in contract C.6 are shot with the harness at 1440 x 1000 and 375 x 812 and checked against the visual contract and these rules. The validation gate below is not part of R4's acceptance: no approved R4 preview exists to compare against (contract D.3).
- Round 3 (2026-10-26): a section edit keeps fields the lead did not change, including a saved writer choice that is not shown while the writer's card is paused. An explicit "No writer yet" choice clears it. A stale save rereads the section, keeps the lead's edits and asks them to check and save again. A reopened busy section says that its earlier change is still saving; every action on that section shares the same write lock. Export keeps an unresolved format choice across closing and reopening, and a late result is reported on the page. Long titles wrap in status lines and item choices; Place choices use one column on every screen. An organizing lead can add a section after existing rows. The latest withheld version explains the next step, a partial save updates the drawer heading, and one downloaded file gets singular wording. These changes remain behind `proposal_v1`; the flags stay off.

## Design standards site (owner direction 2026-10-21)

`/design` is the visual standard that people review and AI agents build from. `/design/` lists the designs. `/design/001/` is navy and gold: the brand from `DESIGN_DNA.md` (logo, thumbnails, print). Videos have their own styles at `/design/v/`. `/design/002/` is this file's green and white app design, with every component, the full chat and the phone layout. Each design has a `tokens.json`, and `/design/catalog.json` lists them all. This file and `DESIGN_DNA.md` record the decisions; when a design page disagrees with them, the file wins until the page is fixed. A new design takes the next number (003) with its own page, tokens file and card on the index. The pages are `noindex` and stay out of the nav and the sitemap. The Tweak panel on each page changes tokens in that browser only.

- Every page has a place to talk (owner direction 2026-10-21). App screens keep their rooms. Every other page carries the page comments box: `assets/page-comments.js` and `assets/page-comments.css`, markup `<div class="pc" data-page-comments data-topic="<page-key>">`. Comments are Community Q&A questions in that topic, and replies are its answers, so they also show on Support. Anyone reads. Members post through `community_ask` and `community_answer` (the room check, daily caps, government accounts read only) and report through `community_report`. States follow chat: loading, an empty line, "could not load" with Try again, and a refused post keeps its words, marked "Not sent yet (kept in this tab)". The `/design` pages carry it now; the rest of the site follows in its own change.
- Plan tiles (owner direction 2026-10-21). A small B (Basic) or P (Pro) tile right after a paid tool, output or ability tells a Free member which plan it belongs to. It stays quiet: 16px, B outlined, P softly filled, a short label on hover or focus, and a link to /plans. Free features get no tile. Pro includes AI, so there is no AI tile. The plan comes from `FedM8Tier.minPlanFor` through `assets/plan-tile.js`, never from page code. A tile the viewer already has goes quieter and drops the link. One tile per tool, and no banners, blur walls or colored controls. Standard and samples: `/design/002/#plan-tiles`.
- Video standards (owner direction 2026-10-23). `/design/v/` lists the video styles and `/design/v/catalog.json` lists them for agents. `/design/v/001/` is the narrated walkthrough, with its reference episode, `tokens.json` and `style.md`. A video of a feature that is not out yet shows "Upcoming FedM8 update · Preview" on every demo frame; a released feature drops it and keeps the sample label. The end card and the address bar say `fedm8.com`, not ai.fedm8.com, which only redirects. Samples use made-up places (Example Base, Example Agency), never a real base, facility or contracting office; department names such as Veterans Affairs are fine on a labeled sample. The 720p reference episode stays in the repo and is replaced in place, not copied. A new video style takes the next number (002) with its own page, tokens file, `style.md` and card.
- Names (owner direction 2026-10-21). The matching AI is Match-M8 in every word a member sees or hears, including video narration and design samples. No engine or vendor name shows. Rooms are hosted by "FedM8 AI". Screens that still show the engine's name get fixed in their own change.

## Visual contract

Paper `#fffef9`, canvas `#f5f3ec`, olive `#526547`, thin muted green borders, dark green text; serif display headings and plain sans-serif controls. Desktop reference is 1440 × 1000; phone reference is 375 × 812. Main content begins about 248px from the left on desktop, with a 190px section rail. Phone uses the six primary sections in a bottom dock (owner direction 2026-10-16: Chat first; Get Certified reads "Certify" there), scrollable public filters, and a single content column. Topic photographs remain above their discussions and become short banners on phones; on the phone Chat home the photograph is left out, because the right-rail card it belongs to sits after the whole stream and the Ask box stays first. Contract search keeps a visible submit button, filters and source/gate facts without a duplicate floating chat shortcut when the native notice entry is available.

## Validation gate

Review categories: layout, navigation, topic discussions, concise copy, mobile behavior, accessibility, feature preservation, privacy. Each requires a positive comparison quality of at least 90% and JEV confidence of at least 0.90. A confident failure is a failure. Missing evidence is not a pass. Routing confidence is unrelated to this gate.

Use matched screenshots of the approved preview and implementation, plus deterministic UI and database tests. Preserve raw JEV distributions, model/revision, source commit, screenshot hashes, environment and test receipts. Visual-only evidence cannot establish privacy or authorization. The local QA harness is excluded from every public deployment. Its signed-in mode uses an unsigned, mock-only session that never reaches Supabase; it creates no real identity and bypasses no database permission. (Updated 2026-10-16: the harness gained that mock-only signed-in mode, `--as free|basic|pro`; this sentence used to say it never creates an authenticated identity.)

Production promotion follows the repository's test-preview approval policy. A passing local screenshot or draft PR does not imply production deployment.

## Homepage buyer experience, October 28, 2026

October 28 owner direction resolves the earlier open homepage hero decision recorded in the October 17 FIX-3 history. The homepage now describes the committed November 11 buyer experience: relevant opportunities, Contract Chat and industry conversations, member connections, prime/subcontractor teams, and proposal preparation. Chat remains the first journey. Free, Basic, and Pro cards explain the benefits of the existing plans; Enterprise remains in development and unavailable for purchase. The existing navy/gold homepage design, release gates, notice-demo disclosure, contact assets, booking target, privacy, and account controls remain. Source mapping and review scope are in `docs/homepage-release-benefits.md`.

## R5 private outcome record client, October 28, 2026

Recorded before implementation against `docs/pursuit/R5-CONTRACT.md` C.1/C.2/E.1. The verified database foundation is migration406; all feature flags remain OFF. The outcome-only client is `assets/pursuit-r5.js`, a standalone module after `pursuit-proposal.js`, with one scoped block in `assets/pursuit.css`. Its guarded team hook adds no route. Its opening hook is inert until a separately reviewed slice implements it.

References are the actual Notion warm-paper notebook and Linear compact-row references recorded and rendered for R2 on October 18: https://styles.refero.design/style/2bf4c61f-de10-4614-ba1b-20c0453bd2a9 and https://styles.refero.design/style/90ce5883-bb24-4466-93f7-801cd617b0d1. No new reference was opened. Reuse their paper, hairline rows and single olive primary action with the existing approved tokens, fonts and dialog stack.

The current lead sees one compact section headed "Private outcome record" after the existing pursuit sections. The ownership and shared-result distinction sit beside its action. An empty journal offers "Record an outcome"; a saved journal shows the reported outcome, event date, state and source summary. Notes and History expand on demand. Editing, marking entered in error and restoration use a drawer with the full report and a required explanation for later revisions. The history remains private and paged. The closed-team explanation is the exact contract sentence; existing closed actions remain closed. Free/Basic current owners can read while Pro enables writes.

One dispatched account/team write owns the lock across drawer close/reopen and every mutation. Unknown results keep their unchanged request key and payload for Retry. Acknowledged receipts trigger a checked reread; stale rereads preserve explicitly changed unsent fields. Status, busy and refusal messages describe only established results. Private text, history and unresolved intent stay in connected-view memory; the module never uses the existing browser-storage draft helpers. Account/team changes and sign-out clear the view and silence late replies.

Phone layouts use the existing full-screen drawer and 44px controls. Rows, status text and 120-character unbroken titles wrap at375/390/768/1280/1440 widths and enlarged text. Keyboard focus returns to the current action; late settlements never reopen an obsolete drawer or steal focus. Exact contract words are preserved under Human Framework and Textbook Teacher. Journal Won never changes shared team results, My Bids, reviews or funded eligibility; the funded hint names the separate "Record the result" action.

## CC-4 team gaps client, October 30, 2026

Recorded before implementation against `docs/pursuit/R5-CONTRACT.md` A.7, C.1 and E.1 and the gap migration `20261101162000_pursuit_gap_reports.sql`. The flag `pursuit_gaps` stays OFF; the section is hidden unless the signed-in `pursuit_r5_status().gaps.enabled` says true (never the browser flag list). The client is `assets/pursuit-gaps.js`, a standalone module after `pursuit-r5.js`, with one scoped block appended to `assets/pursuit.css` and guarded mount and reset hooks in `assets/pursuit.js`. No route, no navigation item, no new tier, no new color, font or component.

References are the actual Notion warm-paper notebook and Linear compact-row references recorded and rendered for R2 on October 18: https://styles.refero.design/style/2bf4c61f-de10-4614-ba1b-20c0453bd2a9 and https://styles.refero.design/style/90ce5883-bb24-4466-93f7-801cd617b0d1. No new reference was opened. Taken: hairline rows on paper instead of cards in cards, ink-only text with a lighter ink for secondary lines, one olive primary action per state, and rows that stay readable at a glance. Not taken: scores, pills, meters, red and any ranking visual; the contract forbids a match score or recommendation here.

Decisions:
- One section, "Check the gaps", on the lead's team page after Evidence and Proposal and before the private outcome record (the section places itself the same way whichever section loads first). Only the current lead sees it, on any plan: the server lets an active lead read, and organizing stays Pro. Rendering the page makes the status read and nothing else; the report is read only when the lead presses "Check the gaps" (a second press reads it again from the start).
- Honest source first: the completeness lines use the R2 words ("2 of 3 files read. 1 could not be read."), then "Found by reading the files. Not checked by a person.", then one line that this reads what is on file and does not check eligibility or choose anyone. A file set that is not complete (some files unread, still being read, not downloaded or not listed yet) adds the contract's line, "These are the lines read so far. Some files may still be unread or unchecked." "No gaps are shown in the lines read so far. Check the notice and its files." never claims every file was read or that the team is eligible.
- Two views, a plain pair of toggle buttons: "Requirement lines" and "Staffing". Requirement lines come in the notice's own order, 50 to a page with "Show more lines"; each row is the line's words (long lines fold with a "Show all" control), then section and type in the R2 type words, then two states in a plain definition list: Work (Not in a work package, Needs your confirmation, or In N work packages) and Evidence (the R3b words Supported, Needs confirmation or Missing, with Expired and File being checked as words). A "Show" choice narrows the lines already loaded (all lines, not in a work package, needs your confirmation, no evidence shown) and says how many lines are loaded of how many; it never counts lines it has not read. State counts appear only once every page is loaded. Nothing is a score, a percentage, a pill or red.
- Staffing rows are one per opening in the team's own order: the opening's title, its kind and state in the R2 words, then Selection (Selection shown or "No selection shown") and Participation (None shown, Waiting for confirmation, Needs re-confirmation or Confirmed, the R3a stage words). A closing line says these views do not say a part is staffed. No capacity, hours, person or private reason appears.
- "Already connected to this team" is a closed disclosure in each staffing row (the read happens when the lead opens it). It lists the people and firms already tied to that opening, alphabetical, each with factual relation words (Team member, Selected for this opening, Responded to this opening) and, under it, what that card has shared with this team: how many items, how many of this work's lines they support, and up to five items by kind, purpose and the three verification words (Self-reported, Source checked, Reviewed by your team) with "This is not an official verification." beside them. The list is never ordered or grouped by fit and never says recommended, best or verified. The lead decides whom to ask from the opening's own invite and evidence actions; this screen performs none.
- Masking is the server's: the client says nothing about people or counts it was not given. A refusal tells the lead only what failed ("This is not open to you." and "Only the team lead can do this." are the contract's own sentences).
- Failure and races, modeled on the outcome record: a late reply after sign-out, a team change or a newer press is ignored and never moves focus; "This list changed. Start the list again." (`stale_read`) restarts that list from its first page; a read that fails says "This did not load. Try again." with Try again; a reply that does not match the contract shape is treated as a failed read, never drawn. Everything private stays in memory in the connected view, drawn as text nodes; the module uses no browser storage, URL, history, console or network call of its own.
- Keyboard and phone: the primary and every control are 44px; after "Check the gaps" focus goes to the first heading of the report, after "Show more lines" to the first new row, after a view change to that view's heading, and after a failure to the message. Status text is announced politely once. Rows and 120-character unbroken names wrap at 375, 390, 768, 1280 and 1440 widths and with enlarged text; on a phone the Work and Evidence entries stack under the line. The two view buttons sit side by side as equal halves while both fit and stack, one to a line, when text is enlarged, so no word of a button is ever cut (the Chromium spec checks this at 28px text). The same section can be shot in the real shell with the QA harness: `--scenario pursuit-gaps` with `_internal/qa-harness/examples/pursuit-gaps-lead.json` (Pro, the lead of T1) or `pursuit-gaps-member.json` (Basic or Free, no section).

# App header, pill nav and account menu (design 003)

The signed-in Workspace has no left rail. `#fm-header` (static in os.html, painted by `paintSidebar()` in `assets/os-boot.js`) holds the logo (Home), one `fm-pill` per space in `FedM8NavOrder` order (the open one is `aria-current="page"`, navy), the bell with the real unread count, Private chats, the firm name and the avatar menu. The avatar menu carries the plan badge, AI credits, My Profile, Account, Appearance, Notification settings, Plans, Support, All tools, Send feedback (the same note as the floating button, which is hidden while the menu entry exists) and Sign out; while the agreement is pending it lists only Account, Notification settings and Support. Tools inside a space are `fm-tabs` under the header (tier chips kept). At 768px and below the pills become a bottom `fm-mobilenav` (Home, Find work, Team Up, Chat, More) and a More sheet with the other spaces and All tools; targets are 44px and the header, bar and sheet clear `env(safe-area-inset-*)`. Styles live in `assets/d3/shell.css` (tokens only). The sign-in, tier and sign-out behavior and the links each tier sees are unchanged. `qc/d3-shell.spec.cjs` measures this in Chromium.
### Public contract brief

The CC1 source extract stays inside the existing Contract Room Brief and uses its approved green-and-white box/disclosure pattern. One short source excerpt appears first; source, exact UTC deadline and stored-file coverage expand under a native “Source and coverage” disclosure. No new navigation, pill row, fake post or paid/private analysis is added. The card appears only for a current validated artifact; missing or unavailable reads leave the existing Brief usable. Long excerpts wrap on phones and source/disclosure controls retain 44px targets. Existing Basic full-summary and requirements gates remain.

The 415 factual continuation reuses that same card, existing design 002 tokens and the previously recorded Notion/Linear disclosure references. It adds a short factual scope rather than an uncited quote, sourced bidder qualifications and location in the existing disclosure, and a Basic “Full cited brief” disclosure. No new page, navigation or design reference is introduced. Source-window coverage and capture/snapshot dates distinguish evidence from completeness. Native keyboard disclosures and text wrapping remain; account changes and plan changes remove paid detail and suppress late responses without clearing unrelated chat drafts. Offline source/component examples at 320/390/768/1280 widths and 200% text use synthetic notices, never production applicant data.

### Ask this contract

Two cards sit under the public brief in the Contract Room, both in the same green-and-white box and native disclosure pattern, with design 002 tokens and no new reference, page, navigation, pill row or fake post.

The free card is headed "Common questions", with one line of lede and one native disclosure, "Show the questions (N of M answered from the notice)". Each answer is a short cited sentence; "Where this comes from" opens the exact words from the public notice. A question the notice does not answer says "Not found" and points to SAM.gov and the room. A footer says what was read and when it was checked, and that attachment contents were not read. One button, "Ask people in the room", moves focus to the room's own composer; the card never posts into the room. It appears only when a complete set exists for the current source revision, and a missing or unavailable read leaves the Brief as it was.

The Pro card is headed "Ask this contract". It states in two short lines what it reads (the contract's documents and the company's saved past performance), that the question is private, and that a returned answer uses one AI credit. One labelled question box (400 characters), one "Ask" button; Ctrl or Command with Enter also asks. A polite status line says "Reading the documents." and the button is disabled while it works, so a double press asks once. Focus then moves to the answer heading. Each statement shows its source label, the place in the source, and the exact words, behind a native "Where this comes from" disclosure. Statements the documents do not back are never part of the answer; they sit behind "Not backed by a document (N)" with a plain warning. "Not found" and "Not about this contract" are first-class answers, say what was read and what it cost, and offer the people in the room, which moves focus to the room's own composer. "Clear this answer" returns focus to the question box. Errors say what happened in one line and keep the question in the box.

Free and Basic members see one short locked note with a "See Pro" link and the room button, never a disabled form. While AI spend is paused the card says so instead of offering a box that would be refused. Nothing is drawn for a signed-out visitor, a feature that is not switched on, or a notice the database does not know.

Private words stay in the page: no browser storage, no cookies, no copy into the room. Plan, account and sign-out changes remove the card and its answer. Server text is always drawn as text. Controls keep 44px targets and a 3px focus ring; long words wrap; the cards fit at 320, 390 and 1280 widths without horizontal scroll. Examples and tests use synthetic notices only.

### Bid checklist and team compliance matrix (CC3)

Three pieces, each in the place the member already works, with approved tokens only (`--fd-*`), hairline rows, one olive action and no new colour, font, pill or card. Free: "Key steps from the notice" sits directly under the public brief, one short ordered list (deadline in the notice's own time zone, how to send the offer, questions, registrations, forms), each line cited to its notice revision or page, "Not found in the notice." where the notice is silent, and a button to the room discussion; it says in one note that software read the notice and a person has not checked it. Basic: "Your private checklist" is one native disclosure inside Notice & requirements, read only when opened; each requirement is a real checkbox named by its words and described by its labels and source; a ticked line that changed says "This requirement changed in a newer version of the notice." Pro: "Compliance matrix" sits under the Proposal section of the team page as a list of row buttons (title, state in words, owner and labels) that open the existing right-hand sheet; the sheet's fields are named, grouped with legends, and Save says what changed.

Accessibility (the R3b practice, checked in Chromium): every control at least 44 x 44, focus ring 2px olive, text 4.5:1 or better, no sideways scroll at 320, 390, 768 and 1280 and in 200% text and WCAG text spacing; `html` keeps a focused control clear of the fixed header and the phone dock with `scroll-padding`. Each section owns one polite and one urgent line made before anything is said and never redrawn with the list; after a redraw that removes the control the keyboard was on, the keyboard goes to the section's heading (or its own line), never to nowhere; a failed read is an alert with one "Try again". Meaning is always in words, never in colour alone. Offline component examples use synthetic notices and teams only.

## R5 employee wage context client, October 30, 2026

Recorded before implementation against `docs/pursuit/R5-CONTRACT.md` B.3, B.4, C.1, C.2, E.1 and E.2 and the migrations `20261101164000_oews_reference_import.sql` and `20261101164100_pursuit_cost_context.sql`. The flag `pursuit_cost_context` stays OFF; the section is hidden unless the signed-in `pursuit_r5_status().cost_context.enabled` says true (never the browser flag list). The client is `assets/pursuit-cost.js` with its own `assets/pursuit-cost.css`, both standalone after `pursuit-r5.js`, and one guarded hook in `assets/pursuit.js` after the Quotes block of the opening drawer (plus the same reset and turned-off hooks the other modules have). No route, no navigation item, no new tier, no new color, font or component.

References are the actual Notion warm-paper notebook and Linear compact-row references recorded and rendered for R2 on October 18: https://styles.refero.design/style/2bf4c61f-de10-4614-ba1b-20c0453bd2a9 and https://styles.refero.design/style/90ce5883-bb24-4466-93f7-801cd617b0d1. No new reference was opened. Taken: hairline rows on paper, ink-only text with a lighter ink for secondary lines, one olive primary action per state, and rows that stay readable at a glance. Not taken: charts, bars, a shared numeric axis, pills, red, meters and any ranking visual; the contract forbids a chart or a graph here and a gray old range.

Decisions:
- One section, "Employee wage context", in the lead's opening drawer after the Quotes block, then a second and separate section, "GSA CALC+ labor ceiling rates", with its own heading, its own two sentences and one reviewed official link (https://buy.gsa.gov/pricing/, `rel="noopener noreferrer"`, opened by the lead's own click). The two never share a row, a table, an axis or a number: CALC+ ships no number, no count, no chart and no fetch. Only the lead of the team sees the section, on any plan: an active lead reads their own saved snapshot on Free, Basic and Pro; choosing, changing, clearing and confirming again are Pro, shown as the contract's one sentence "Organizing a pursuit is part of Pro." in place of the buttons. The server decides every one of these; the page only mirrors it.
- Opening the drawer makes the status read and one context read and nothing else. No option list, no wage, no search is read until the lead presses "Choose an occupation and area". The page never guesses a revision: the context read supplies the opening and work-package revisions and the choice revision (also for an empty choice, a cleared one and one that needs confirming again), and a save is sent only after a successful read.
- The chooser is an inline panel inside the section, not a second dialog (a dialog over the drawer would close the drawer it belongs to). It has four groups in the contract's order: Source period (a radio list of the offered releases, each with its reference period and publish date; nothing is called latest or newest), Occupation (a literal title search, 50 to a page with "Show more", each row its code and title, the duties of the selected row shown under it and tied to it for screen readers), Area (the same list; the U.S. is a row like any other, never preselected, and there is no city or ZIP), and Pay unit (Per hour or Per year, nothing preselected). A closing line says exactly what will be saved, then one primary action, "Show wage context". If something is missing the panel says which group, and moves focus to it; nothing is sent.
- A title suggestion is a word, never a choice: when the opening's labor category (else its title) equals an occupation title ignoring case and spacing, that row carries "Matches this opening's labor category". The lead still selects the row, reads its duties and presses the primary action; the saved method then reads exact title confirmed, and the server checks the equality again. Stemming, plurals, fuzzy matching and any model are not used. No state is suggested: the notice has no structured place of performance, and a guessed area is not offered.
- What is shown follows the server's checked snapshot only. A published range reads exactly as the contract's sentence with the three published decimals formatted in US dollars without changing their precision and "per hour" or "per year", then one line with the source period, the publish date and the retrieval date, then "This is dated source context, not a claim that these are the newest figures." When the source gives no usable range the section says why in the contract's words (not published, a bound, or marked unavailable or unusable) and shows no number, no zero and no empty chart. A choice whose opening or work package changed says so and asks to be confirmed again; a withdrawn source says it was withdrawn; neither draws a faint old range. "Source details" is a native disclosure with the program, the release dates, the industry and ownership selection, how the choice was made and the official files, each file a link only when its address is on the exact reviewed hosts.
- Failure and races follow the outcome record: one write lock per opening that survives the drawer being closed and opened again; a refusal or lost reply after close is told once when the drawer next shows that opening; "This did not load. Try again." for any failed read; the contract's stale, unknown, busy and read-back sentences exactly; a stale save rereads, keeps the lead's selections and asks them to check and save again; a lost reply keeps the same request key and offers Retry of the same change. Replies are checked against the exact reply shape before anything is drawn. Replies, selections and the lock stay in memory in the connected view, drawn as text nodes; the module uses no browser storage, URL, history, console or network call of its own, and sign-out or an account change clears all of it and silences late replies.
- Keyboard and phone: every control is 44px; the chooser opens with focus on its heading, a search runs on Enter and says how many rows it found, "Show more" moves focus to the first new row, a save moves focus to the section's status, Cancel returns to the button that opened the panel. Status text is announced politely once and refusals use an alert. Rows, titles and 120-character unbroken names wrap at 375, 390, 768, 1280 and 1440 widths and with enlarged text; on a phone the buttons take the full line.
- Nothing here is a quote, a bid recommendation, a wage determination or advice, and the section says so in one plain sentence. Nothing is copied into a quote, a worksheet or a rate; viewing, choosing, refreshing and clearing change nothing else.
