Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / docs/DIRECTIVE_AMENDMENTS_CONSOLIDATED.md |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 720d47fae476b0d38477ae4401697d372b1ea2bc |
| Branch | feature/opportunity-to-outcome |
| Path or archive member | docs/DIRECTIVE_AMENDMENTS_CONSOLIDATED.md |
| Original SHA-256 | a54d8697d99d792760bf91f68648cf2a513fbfeab5b19ad5eec4ba6680e05f71 |
| Git blob SHA | d9588fed5ef0b87d62e8b91356c7ed193985568b |
| Reading-copy SHA-256 | a54d8697d99d792760bf91f68648cf2a513fbfeab5b19ad5eec4ba6680e05f71 |
Recovered source transcript
Download complete source text ↓724 lines · 38.8 KB
# DIRECTIVE AMENDMENTS 1 THROUGH 5, CONSOLIDATED
Companion to docs/CLAUDE_CODE_BUILD_DIRECTIVE.md. Generated 27 July 2026.
This file supersedes the five individual amendment files. Conflicts are
pre resolved: Amendment 3's corrections are already applied inside the
Amendment 2 content below. There is nothing to reconcile. Apply this file
and the directive together as the complete work order.
--------------------------------------------------------------------------------
0. AUTONOMOUS APPLICATION PROTOCOL
--------------------------------------------------------------------------------
1. Read order: CLAUDE.md, docs/CLAUDE_CODE_BUILD_DIRECTIVE.md, this file,
docs/BUILD_STATE.md. Then apply.
2. Record "amendments 1 through 5 accepted, consolidated" in BUILD_STATE
with the date and this file's path.
3. If individual amendment files exist under docs, move them to
docs/archive. Exactly one amendment source may exist: this file.
4. Merge map: Amendment 1 appends to directive Section 0 as an
environment rule. The slate approval lifecycle merges into Phase 3
and Gate 3. Desk integration, publishing, the Import Center, the
Candidates page, and the desk dataflow merge into Phase 5 and Gate 5.
The canonical dataflow becomes a permanent directive appendix.
Acceptance items 25 through 35 append to directive Section 11. Task
T1 registers as standalone work outside the phase gates.
5. Passed gates are never reopened. If an item conflicts with work
already completed, record the conflict in BUILD_STATE, choose the
smallest change that satisfies both, and note it. If no such change
exists, stop and surface it.
6. Autonomous operation: proceed phase by phase without waiting for
permission. Verify every gate against staging, record evidence in the
ledger, and continue. Surface to Joseph only for these four things:
any Phase 0 human blocker not yet recorded in the ledger, the vhost
confirmation for Task T1 if the target is ambiguous, review of the
two nginx location blocks before anything touches the live
fg-talent.com vhost, and the Gate 6 production cutover.
7. Every directive rule stands unchanged: staging only until Gate 6,
meaning missionmatch_staging on M4 port 5432 (see the corrected
location note directly below); the candidate
scoring engine is frozen; forced RLS and organization_id on every
tenant table; extend, never build beside; fail closed; no Python; no
dashes in written output, hyphens only in code identifiers, protocol
headers, and official designations.
--------------------------------------------------------------------------------
AMENDMENT 1: ENVIRONMENT RULE
--------------------------------------------------------------------------------
CORRECTED LOCATION, ratified by Joseph 28 July 2026. This file originally
named staging as missionmatch_staging on megamind-agi port 5433. That
database exists but is an EMPTY SHELL: zero organizations, zero
candidates, and a goose_db_version table the app role cannot even read.
IT MUST NOT BE USED. The functioning staging, and the only one this
directive means, is:
missionmatch_staging on M4, 100.94.8.94, port 5432
That is the database the live mm-api-staging service on 127.0.0.1:8097
serves, it carries real working data, and it is the only staging target
that can satisfy a gate, because a gate requires an end to end check
through a live authenticated API and a rendered screen.
Every migration, every live database verification, and every end to end
check through Phase 5 runs against missionmatch_staging on M4 port 5432.
The production tenant database is touched only at Gate 6, and only after
the backup and restore test passes. If any task appears to require
production before Gate 6, stop and record the conflict in BUILD_STATE
instead of proceeding.
The three Phase 0 human blockers, revoking the exposed OpenAI key,
placing the fresh project scoped key on M4 as openai_api_key root owned
0600, and starting the SAM.gov system account application, were recorded
as ledger events when Joseph completed them. If any of the three is
absent from the ledger, do not enable anything external and surface it.
--------------------------------------------------------------------------------
AMENDMENT 2, AS CORRECTED BY AMENDMENT 3:
WORKFLOW COMPLETION AND PUBLIC SURFACES
--------------------------------------------------------------------------------
2.1 DECISIONS RECORDED
1. Slate approval becomes a lifecycle: proposed, approved, withdrawn.
Approval writes into proposal staffing links and readiness.
Withdrawal exists, requires a reason, and is fully audited. Amends
Phase 3.
2. screenMATCH and resumes wire into the recruiting desk through the
shared candidate record and a requisition to requirement bridge. The
frozen engine is reused through that bridge, never duplicated. Amends
Phase 5.
3. The primary public jobs surface is the tenant company's own website.
fg-talent.com is the first and the reference implementation. For a
mapped tenant, candidates never see the missionMATCH domain.
4. Serving pattern: nginx on Bubbles proxies fg-talent.com/careers/ to
the mm_api public jobs handler, which renders complete server side
HTML from Go templates, branded for the tenant. Crawlers and
visitors receive real HTML in the initial response. No client side
rendering of job content anywhere. This is chosen over static file
generation because it serves the same real HTML while updating the
instant a recruiter publishes or fills an order, one rendering path
instead of two.
5. Tenant site mapping, configuration not code: tenant_slug,
public_base_url (https://fg-talent.com/careers), brand template,
consent notice reference. A mapped tenant's jobs path on the
missionMATCH domain issues a 301 to the tenant domain. Unmapped
tenants may use the app domain hosted jobs page.
6. Apply is same origin on the tenant domain. fg-talent.com/careers/apply
proxies to the mm_api apply intake. A submission creates or dedupe
matches a candidate and creates an application in the applied stage
in the FG Talent tenant, source career_site, consent event stored
with notice version, honeypot plus an nginx limit_req zone on the
apply path modeled on the existing mm_auth zone.
7. Nothing is ever posted to Google. Indexing follows the house SEO
rules and nothing else: a careers sitemap section regenerated on
every publish and unpublish, internal links from the careers index
and site navigation, GSC Request Indexing, and the URL Inspection
API. JobPosting JSON-LD remains on each job detail page as standard
on page schema, one block per canonical URL, mirroring the visible
content, because it makes the fg-talent.com pages themselves surface
in search and answer engines. That is the entire role Google plays.
8. Expiry discipline: on fill, close, or validThrough passing, the page
unpublishes, the sitemap entry drops, and the markup is gone,
enforced by cmd/jobs-expiry-sweep, idempotent like everything else.
9. FG Talent content rule, enforced in template and in test: only
Patricia Cox and Brian Atwood may appear anywhere on the public site
or in schema. Tom and Glennette are excluded from every page, every
JSON-LD block, every hiringOrganization contact, and every authored
by field. hiringOrganization is FG Talent Partners.
10. Public surface hygiene: published fields only, never bill rates,
margins, internal notes, or client names without the per requisition
flag; tenant resolved by slug only, never by organization id;
unknown slug returns 404 with nothing leaked; zero EEO adjacency on
any public surface.
11. The marketing site login button is standalone Task T1, executed on
the Bubbles vhosts, outside the phase gates and outside the
missionMATCH repo.
12. The client portal read surface is deferred to fast follow, but its
data model, client submittals with feedback and reason codes, ships
now in Phase 5, so the portal later is a rendering task, not a
migration.
13. Pay range fields on publish are optional, but the publish screen
warns when the posting location or remote eligibility touches a
state requiring a range in the posting: California, Colorado,
Hawaii, Illinois, Maryland, Massachusetts, Minnesota, New Jersey,
New York, Vermont, Washington, and the District of Columbia.
14. Automated candidate outreach on status changes is deferred to fast
follow. Status changes create alerts and draft notifications a human
sends. Deterministic triggers only.
2.2 TASK T1: MARKETING SITE LOGIN BUTTON
1. Enumerate the nginx vhosts on Bubbles and identify where missionMATCH
is marketed publicly. The application lives at
https://missionmatch.thatwebhostingguy.com, so the button belongs on
the marketing surface, not inside the app.
2. If the target is ambiguous, list the candidate vhosts for Joseph in
one message and wait for his pick. Do not guess on a production
website.
3. Add a prominent Log in button in the site header and hero linking to
https://missionmatch.thatwebhostingguy.com. Static HTML, CSS, and
vanilla JS, brand consistent, no framework, no Python.
4. If no marketing page exists, say so and build a single branded page,
hero, product line summary, and Log in, at the vhost Joseph names.
5. Verify rendered in a browser over HTTPS before recording done.
2.3 AMENDMENT TO PHASE 3: SLATE APPROVAL LIFECYCLE
1. Slate member decision becomes a lifecycle with columns on the
existing slate member record: status in proposed, approved,
withdrawn, plus approved_by_user_id, approved_at,
withdrawn_by_user_id, withdrawn_at, and withdrawal_reason.
withdrawal_reason is required on every withdrawal and stored.
2. Approve, one transaction taking FOR UPDATE on the member row: set
status and stamps, and where the slate is linked to a proposal,
increment proposal_staffing_links.approved_count. Audit through
OnTx. The approval appears in the proposal Staffing tab, readiness
inputs, and slate exports with who and when.
3. Withdraw, same transaction discipline: requires the reason, sets
status and stamps, decrements approved_count, audits, and flags the
latest readiness snapshot stale. Withdrawal never deletes anything.
4. Re approval after withdrawal is allowed. The audit trail carries the
full sequence.
5. Both actions use the existing slate decision capability. Both notify
the capture owner and proposal owner through the alerts module.
6. UI: approve and withdraw buttons on the slate member row, withdraw
opens a reason modal, the row shows current status with the latest
stamp.
GATE 3 ADDITIONS: approve, withdraw, and re approve leave approved_count
exactly correct under an eight way race, proven by racing it. A
withdrawal without a reason is rejected by the API, not just the form. A
withdrawal flips readiness staleness and the next snapshot reflects the
reduced coverage. The full sequence is visible in the audit trail.
2.4 AMENDMENT TO PHASE 5: DESK INTEGRATION
A. Requisition to requirement bridge. Requisitions gain requirement_id.
Creating a job order offers two paths: link an existing requirement,
or create and link one using the same structured requirement fields
the platform already scores against. The frozen engine is reached
only through this bridge. Editing the linked requirement after
screenings exist marks those screening results stale, never
silently.
B. Resume pipeline. Resume upload on the candidate record and through
the apply intake: sha256, versioned, stored through
internal/platform/storage, current flag, priors retained. Parsing
runs through docextract and extraction into draft profile
suggestions: skills, certifications, experience entries, and
clearance indicators always labeled clearance intelligence, self
reported. Suggestions are accepted or edited by the recruiter,
never silently applied. Duplicate detection on candidate create and
on apply matches email and phone and prompts to open or merge.
C. Screen from the desk. On an application row, a Screen action runs
the screenMATCH evaluation against the requisition's linked
requirement. The result, score, band, caps applied, engine version,
timestamp, stores on the application and renders in the pipeline.
Re screening keeps history. A stale badge shows when the
requirement changed after the screening ran. screenMATCH's queue
lists desk originated screenings.
2.5 AMENDMENT TO PHASE 5: PUBLISHING TO THE TENANT WEBSITE
1. Requisition publish workflow. Visibility: internal_only or
published. Public label: open, on_hold, filled, closed. The publish
checklist requires title, public description, location or remote
with explicit applicant location requirements, employment type
(arrays supported, contract to hire is CONTRACTOR plus FULL_TIME), a
validThrough date, and apply enabled. Pay range and benefits
description are optional with the state warning from decision 13.
2. mm_api public jobs handler renders three things per mapped tenant:
the careers index at public_base_url, one canonical detail page per
published open job at public_base_url plus a stable job slug, and
the apply endpoint. Canonical link tags point at the fg-talent.com
URLs. Cache headers allow nginx to cache briefly, purged on publish
and unpublish. Each detail page carries exactly one JobPosting
JSON-LD block mirroring the visible content: title, description,
datePosted, validThrough, hiringOrganization as the tenant,
jobLocation or remote with applicantLocationRequirements,
employmentType, optional baseSalary, and identifier as a
PropertyValue holding the internal requisition id. No JobPosting
markup on the list page.
3. The nginx change on the fg-talent.com vhost is two location blocks
matched to that vhost's conventions: one proxying /careers/ to the
mm_api upstream with the tenant slug fixed server side, one for
/careers/apply with the rate limit zone. Claude Code drafts the
exact blocks, Joseph reviews before they touch the live vhost, and
the reload is verified with the zero 5xx sweep. The careers index
gets an internal link from the main navigation as part of the vhost
change.
4. The brand template for FG Talent matches the existing site design
language, header, footer, typography, colors, so the careers
section reads as native.
5. Embeddable feed. GET /jobs/{tenant_slug}/feed.json returns published
open jobs, and a small vanilla JS embed snippet renders them on any
other page, documented. For a mapped tenant the canonical
destination is always the proxied careers page.
6. Apply intake, minimal: name, email, phone optional, resume upload,
and a consent checkbox rendering the tenant's configured notice
text from the Phase 4 notice system. Submission creates or dedupe
matches a candidate, creates an application in the applied stage,
records source career_site, stores the consent event with timestamp
and notice version. Honeypot plus rate limiting. Rollout beyond FG
Talent is one mapping row and one nginx block per client site.
2.6 AMENDMENT TO PHASE 5: DESK WORKFLOW ADDITIONS
1. Structured intake brief on every job order, three fixed blocks: role
context, candidate profile, and submission logistics, where
logistics means fee or rate terms, required submittal format, client
feedback SLA, interview process, and the approval contact. Sourcing
from an incomplete brief shows a warning, not a hard block.
2. Pipelines per placement type. Job order type, permanent, contract,
contract to hire, temp, selects the stage template automatically.
3. Client submittal records as explicit steps distinct from internal
submittal: packet reference, submitted_at, client feedback text, a
feedback reason code, and a feedback SLA timer that ages visibly.
This is the data model the future client portal renders.
4. Reason taxonomy on every rejection and every backward stage move,
selected from a small configurable list plus free text. Reasons feed
the intake quality loop and the segregated adverse impact reporting
path, through the compliance role only, never the other direction.
5. Days in stage aging on the pipeline board, thresholds configurable
per tenant, default flag when interview stage aging passes fifteen
days.
6. Wire the existing activities and tasks tables into every record
surface: notes timeline and tasks with owners and due dates on
candidates, clients, requisitions, applications, and placements.
7. Talent pools and saved searches: named candidate lists per recruiter
and team, add from any candidate list, saved search definitions, so
a repeat job order starts from the last search instead of zero.
8. Status triggered alerts through the alerts module: stage change,
client feedback recorded, offer accepted or declined, assignment end
approaching. Drafted notifications, human send, per decision 14.
9. Offers completed: status enum with extended, accepted, declined
stamps and a decline reason. Placement creation carries worksite,
pay rate, bill rate, start date, and approval contact forward from
the order and offer without retyping.
10. Optional requisition approval chain per client: when a client is
flagged as requiring it, a manager approval step gates the order
going active.
11. Client specific submittal requirements live on the client record,
format notes and process notes, surfaced automatically at submittal
time.
2.7 FAST FOLLOW ADDITIONS
Append to the directive's fast follow list: the client portal rendering
the submittal and feedback model, read only, per client contact
authentication; automated candidate engagement sequences on status
triggers once a sending policy is decided; VEVRAA ESDS posting reusing
the publish pipeline as its source of truth; knockout questions and
reference check records on applications; a placement start onboarding
checklist; and requisition and placement history import.
2.8 GATE 5 ADDITIONS, PUBLISHING AND DESK
1. Publish a job order in recruitMATCH and load it at
https://fg-talent.com/careers/ and its detail URL. curl shows the
full job content in the initial HTML response, no JS execution
required.
2. The detail page carries exactly one JobPosting JSON-LD block that
mirrors the visible content and passes the Rich Results test.
3. Submit the apply form from fg-talent.com: a candidate and an
application exist in the FG Talent tenant, stage applied, source
career_site, consent event stored with notice version, and the
duplicate check fires on a repeat email.
4. Fill the order: the detail page is gone, the index no longer lists
it, the sitemap entry is removed, and the markup is nowhere.
5. The missionMATCH domain path for the FG Talent slug issues a 301 to
fg-talent.com.
6. Page and schema contain Patricia Cox and Brian Atwood only. A test
asserts the strings Tom and Glennette appear nowhere in rendered
output or JSON-LD.
7. Unknown slug returns 404 with nothing leaked, and the apply rate
limit answers 429 under the race.
8. The careers sitemap section regenerates on publish and on unpublish,
and GSC Request Indexing is exercised once manually and recorded.
9. The feed renders on a test page.
10. Screen from an application stores a banded result and goes stale
when the requirement changes. Resume parse produces suggestions and
never overwrites. Duplicate detection fires on a known email.
11. An intake brief saves with all three blocks. A client submittal
records feedback with a reason code and its SLA timer ages. A
rejection carries a taxonomy reason. An accepted offer flows into a
placement carrying rates forward.
2.9 ACCEPTANCE ADDITIONS
25. Slate approval and withdrawal maintain correct counts under race,
and every withdrawal carries a stored reason.
26. Public jobs surfaces expose only published data, resolve tenants by
slug only, and pass Rich Results validation on every live posting.
27. Expired or filled postings drop their markup immediately, verified
by the sweep job's test.
28. Apply intake stores a consent event with notice version for every
submission.
29. Desk screenings reach the engine only through the requisition to
requirement bridge, and the engine diff remains empty.
--------------------------------------------------------------------------------
AMENDMENT 4: UPLOADS AND THE IMPORT CENTER
--------------------------------------------------------------------------------
4.1 DECISIONS RECORDED
1. One upload subsystem, three entry points: the candidate record, the
recruitMATCH Import Center, and screenMATCH screen from resume.
Parsing, deduplication, storage, and versioning exist in exactly one
internal path that all three call. The apply intake uses the same
path.
2. Every bulk import is staged, never direct. Files land in
import_batches and import_rows, then validate, then preview, then a
human commit writes live records. Extract, draft, review, approve,
promote.
3. Import types shipping in Phase 5: single resume, resume bundle as
multiple files or one zip, candidate spreadsheet as CSV or XLSX, and
clients with contacts spreadsheet.
4. Protected class columns are rejected at validation, by name pattern
and content sniffing: race, ethnicity, gender, sex, disability,
veteran status, and kin. EEO and self identification data never
enters through an import. The segregated compliance path is the only
door.
5. Every imported candidate carries source import with a batch
reference, and committing a batch requires a first party attestation
checkbox, the tenant affirming the data was collected by their
organization from the candidates directly. The attestation, who, and
when are stored on the batch.
6. File rules. Resumes: pdf, docx, txt, rtf, legacy doc rejected with a
clear resave message. Data: csv, xlsx. Bundles: zip only under the
archive safety rules. Size caps and per batch row caps are
configuration with sane defaults.
7. Processing is asynchronous through a job binary. The UI shows live
progress and per row outcomes. Partial success is normal. Batches
are idempotent and resumable: every row records its action, reruns
skip completed rows.
4.2 DATA MODEL
All tables carry the standard invariants.
import_batches: organization_id, id, kind, status, source_file_name,
storage_key, sha256, size_bytes, row_count, created_count, merged_count,
skipped_count, failed_count, dedupe_policy, mapping_id,
attestation_checked, attestation_user_id, attestation_at,
created_by_user_id, started_at, completed_at, created_at. kind enum:
resume_single, resume_bundle, candidates_sheet, clients_sheet. status
enum: uploaded, validating, ready_for_review, committing, completed,
completed_with_errors, failed, cancelled. dedupe_policy enum: prompt,
merge, skip, create.
import_rows: organization_id, id, batch_id, row_number,
source_file_name, raw_content_ref, parsed_payload, validation_errors,
dedupe_match_candidate_id, action, created_candidate_id,
created_client_id, created_contact_id, error_code, processed_at. action
enum: pending, created, merged, skipped, failed. Nothing here is a live
record until commit writes one and stores its id back on the row.
import_mappings: organization_id, id, kind, name, column_map,
created_by_user_id, created_at, updated_at. Saved column mappings so a
recurring spreadsheet format maps once.
Resume storage and versioning reuse the candidate record model: sha256,
versioned, current flag, priors retained, bytes through
internal/platform/storage.
4.3 IMPORT CENTER, IN recruitMATCH
1. Upload screen: import type picker, drag and drop with a file picker,
multiple files for bundles, single zip accepted, live progress,
allowlist and size enforcement with clear per file errors.
2. Mapping screen for spreadsheets: source columns to candidate or
client fields, automatic suggestion by header name, saved templates
offered on header match, required field indicators, protected class
rejection surfaced here with the offending columns named.
3. Review screen: counts by outcome, validation errors per row, dedupe
resolution with the batch policy as default and per row override,
matches shown side by side with the incoming row.
4. Commit: attestation checkbox, then asynchronous commit with live
progress, final counts, and a per row error export through csvsafe.
5. Batch history: every batch with status, counts, uploader, drill in
to rows. Cancellable before commit. Nothing about a committed batch
is ever deleted.
6. Quick add stays: the single candidate form with inline resume
upload, wired to the same subsystem.
4.4 screenMATCH ADDITIONS
1. Screen from resume, single: upload one resume inside screenMATCH,
parse to draft profile, dedupe prompt on match, recruiter confirms
create or use existing, selects the requirement, evaluation runs.
Result stores with engine version and timestamp. Candidate carries
source resume_upload.
2. Bulk screen against one requirement: upload a resume set or zip, a
resume_bundle batch is created with the requirement attached, and on
commit every created or matched candidate is evaluated against it.
The screening queue fills with banded results, failures listed per
file, nothing uncommitted is ever scored.
3. Archive safety wherever zip is accepted: list entries first, enforce
per entry allowlist and size cap, cap entry count, reject nested
archives, reject path traversal. Extraction only after the listing
passes.
4. The frozen engine is reached only through the existing evaluation
path.
4.5 PROCESSING
1. cmd/import-process: claims a batch, parses, validates, computes
dedupe candidates, and executes commit, each step bounded,
observable, audited, idempotent by row action, following the
sam-sync and queue conventions.
2. Parsing through docextract and extraction. Spreadsheets parse in Go.
Per row failures never abort the batch.
3. Large file behavior tested: a batch at the row cap completes with
memory bounded through streaming reads.
4.6 GATE 5 ADDITIONS, IMPORTS
1. Commit a three file resume bundle: three candidates exist with
parsed suggestions, sources read import, each traces to batch and
row.
2. A planted duplicate triggers the dedupe prompt and a merge produces
one candidate, not a twin.
3. A spreadsheet with a protected class column is rejected at
validation with the column named, and nothing reaches a live table.
4. A five hundred row candidate spreadsheet commits with correct
counts, per row lineage, and a clean error export.
5. Kill cmd/import-process mid commit and rerun: the batch completes
with no duplicates, proven by counts.
6. Screen from resume produces a stored banded result and the dedupe
prompt fires on a known email.
7. A bulk screen fills the screening queue and lists the one
deliberately corrupt file as failed.
8. A zip with a path traversal entry and a zip with a nested archive
are both rejected at listing.
9. Every commit stores the attestation with user and timestamp.
10. An uncommitted batch is invisible to candidates, search, matching,
and slates, proven by query.
4.7 ACCEPTANCE ADDITIONS
30. No import writes a live record except through a committed batch, and
every imported record carries batch and row lineage.
31. Protected class data cannot enter through any import path, proven by
the rejection tests.
32. Import batches are idempotent under rerun and partial failure, with
counts that always reconcile to rows.
--------------------------------------------------------------------------------
AMENDMENT 5: THE CANDIDATE SPINE AND THE DESK DATAFLOW
--------------------------------------------------------------------------------
5.1 THE CANONICAL DATAFLOW, PERMANENT DIRECTIVE APPENDIX
One candidate spine. One linking record. Everything hangs off it.
INTAKE CANDIDATE WORK
apply on fg-talent.com \ / desk pipeline
Import Center bulk \ / (applications)
screenMATCH resume > candidates table < proposal slates
quick add on the desk / one record per person \ screenings
(all paths dedupe) / all tools, same spine \ pools, searches
THE LINKING RECORD: application (candidate x requisition)
exactly one active application per candidate per requisition
requisition (job order, openings count, linked requirement)
|
| add to job order (from match, search, pool, or manual)
v
application: prescreen -> internal submittal -> client submittal
-> interview -> offer -> placed
or out at any stage, always with a reason code
|
| offer accepted
v
placement takes a seat under the existing FOR UPDATE seat lock
|
v
JOB ORDER UPDATES ITSELF
stage counts derive live on the order
last seat placed flips status to filled in the same transaction
remaining active applications become filled_by_another, notified
filled unpublishes the fg-talent.com page via the expiry sweep
a fall off frees the seat, reopens the order, alerts the owner,
and never republishes without a human confirming
|
v
placement end approaching -> redeployment alert -> candidate returns
to the available pool -> the spine loops
Both match directions use the same frozen engine: a job order ranks
candidates, and a candidate ranks open job orders, both reading through
the requisition to requirement bridge. screenMATCH is the deep evaluation
of one pairing, stored on the application. slateMATCH is the proposal
branch off the same spine, and a person may sit on a slate and in a desk
pipeline at once because both point at one candidate record.
5.2 DECISIONS RECORDED
1. One candidate spine. The missionMATCH command center Candidates
screen and the new desk page read the same records. Shared candidate
profile components are extracted into a shared frontend directory
and composed by both surfaces. Nothing candidate shaped is
duplicated per tool.
2. recruitMATCH gains a Candidates page in its navigation, gated by the
recruitmatch entitlement.
3. Candidate search on the page is deterministic SQL: the existing
hybrid fusion, tsvector rank with pgvector cosine joined by
reciprocal rank fusion, exposed as a repository query with
structured filters. The AI Ask path is untouched and separate.
4. Reverse matching runs the frozen engine, one candidate against the
linked requirement of every open requisition. Orders without a
linked requirement appear as unmatchable with a fix it link to the
bridge. Every computed pairing persists with score, band, engine
version, and computed_at, and goes stale when the requirement or the
candidate profile changes after computation.
5. Add to job order creates the application. Exactly one active
application per candidate per requisition, enforced by a partial
unique index over non terminal statuses. Adding a candidate whose
prior application on that order ended requires an explicit reopen
with a taxonomy reason.
6. Applications record how they began: added_from in apply, import,
match, search, pool, manual, screen. When added from match, the
score snapshot, band, and engine version at add time are stored on
the application.
7. The default stage template gains internal_submittal and
client_submittal as explicit stages. Existing stage values are never
renamed and never destroyed; the template extends, historical data
stands, derive.go and analytics read the extended set. Placement
type templates build on this default.
8. Job order status is a state machine: draft, open, on_hold, filled,
closed. Filling the last seat flips open to filled automatically
inside the placement transaction the seat lock governs. A fall off
frees the seat and flips filled back to open automatically, with an
alert. Manual transitions remain, and every transition, automatic or
manual, is audited with its cause.
9. filled_by_another is a distinct application outcome, not a
rejection. When an order fills, remaining active applications move
there in the same transaction, their candidates flagged available,
owners notified through alerts.
10. Republishing after a fall off requires a human confirm on the
requisition. The page never reappears on fg-talent.com silently.
5.3 THE CANDIDATES PAGE, IN recruitMATCH
1. Roster list: name, headline or current title, clearance intelligence
level, top skills, location, availability, source, last activity,
active pipelines count, pools. Sortable, virtualized.
2. Filters: clearance intelligence level, skills, certifications,
location and radius or remote, availability window, source, pool,
has resume, last activity age. Free text runs the fusion query.
Saved searches apply here, save and rerun.
3. Bulk actions on selected rows: add to pool, add to job order, export
through csvsafe.
4. Candidate detail, composed from shared components, tabs: Profile
(clearance intelligence always labeled self reported), Resumes
(version list, inline viewer, download, upload new version),
Screenings (every screenMATCH result with engine version, band, and
stale badges), Pipelines (every application across orders with
client, order, stage, status, aging), Activity and Tasks, Pools.
5. Detail actions: Match to open orders, Add to job order, Screen
against an order, Add to pool, Edit profile, Upload resume.
5.4 REVERSE MATCH, CANDIDATE TO OPEN ORDERS
1. Match to open orders opens a ranked list: every open requisition
with a linked requirement, scored by the frozen engine, showing band
chip, score, client, order title, openings remaining, deadline or
aging, and whether this candidate already has an application there.
2. Row actions: Add to pipeline, creating the application with the
match snapshot, and Screen now, running the full screenMATCH
evaluation on the pairing. Multi select add supported.
3. Unmatchable orders list at the bottom with a link opening the bridge
flow.
4. Determinism: same candidate and same open orders produce the same
ranking every run, decimal arithmetic, no model in the loop. Stale
pairings recompute on open; persisted history is never overwritten.
5.5 ADD TO JOB ORDER, MECHANICS
1. One transaction: FOR UPDATE on any existing application row for the
pair, insert or reopen, write added_from and the snapshot when
present, write the activity, audit through OnTx. Eight racing adds
produce one application.
2. Requisition list and detail show live stage counts, in pipeline,
internal submittal, client submittal, interview, offer, placed, and
out, derived by indexed query, plus openings remaining from
placements. Stat tiles click through to the filtered pipeline.
3. Client detail shows its orders with the same counts, so find a
candidate, match them, add them to the client's open order is two
clicks from either end and the order reflects it immediately.
5.6 JOB ORDER SELF UPDATES
1. Filling the last seat, inside the placement transaction: requisition
status to filled, remaining active applications to filled_by_another
with notifications, publish state to unpublished with the sitemap
entry dropped by the sweep, audited with cause placement_final.
2. Fall off: a placement ending before its scheduled end frees the
seat, flips filled to open with cause fall_off, alerts the order
owner and the capture owner where linked, leaves the page
unpublished pending human republish. filled_by_another candidates on
that order can be reactivated to their prior stage manually, one
click, audited.
3. on_hold pauses publishing and SLA timers without disturbing the
pipeline. closed is terminal, requires a reason, moves active
applications to out with reason order_closed.
5.7 GATE 5 ADDITIONS, CANDIDATES AND DATAFLOW
1. The Candidates page finds a planted candidate by skills filter and
by free text through the fusion query, and the missionMATCH command
center Candidates screen still renders from shared components with
zero regression.
2. Reverse match on a fixture candidate returns an identical ranking
across repeated runs, and the engine diff against the starting
commit remains empty.
3. Add to job order from the match list creates the application with
the score snapshot and added_from match. Eight racing adds of the
same pair produce exactly one application. A duplicate add through
the API is rejected.
4. Stage counts on the requisition update as the application moves
through prescreen, internal submittal, client submittal, interview,
and offer, and each tile clicks through correctly.
5. Placing the final seat flips the order to filled, moves remaining
fixture applications to filled_by_another with alerts recorded, and
the fg-talent.com detail page and sitemap entry are gone.
6. A simulated fall off frees the seat, reopens the order with an
alert, does not republish, and a one click reactivation restores a
filled_by_another candidate to their prior stage, audited.
7. Re adding a previously rejected candidate demands a reopen reason
and records it.
8. A candidate on a proposal slate and in a desk pipeline resolves to
one candidate id everywhere.
5.8 ACCEPTANCE ADDITIONS
33. Exactly one active application exists per candidate per requisition,
enforced by the database, proven by the race.
34. Every job order status transition, automatic or manual, carries an
audited cause, and filled_by_another is distinguishable from
rejection in every report.
35. Reverse match rankings are bit reproducible, persisted with engine
version, and the frozen engine remains untouched.
--------------------------------------------------------------------------------
FINAL MERGE INDEX, VERIFY AFTER APPLYING
--------------------------------------------------------------------------------
1. Directive Section 0 gained the Amendment 1 environment rule.
2. Phase 3 gained the slate approval lifecycle. Gate 3 gained its
additions.
3. Phase 5 gained: desk integration A through C, publishing to the
tenant website, desk workflow additions 1 through 11, the Import
Center and screenMATCH uploads, the Candidates page, reverse match,
add to job order, and job order self updates. Gate 5 gained sections
2.8, 4.6, and 5.7.
4. The directive gained the canonical dataflow as a permanent appendix.
5. Section 11 gained acceptance items 25 through 35.
6. Task T1 is registered as standalone work.
7. The fast follow list gained the 2.7 items.
Record "consolidation merged and verified" in BUILD_STATE when all seven
lines above are true in the working plan.